diff options
author | thomascube <thomas@roundcube.net> | 2005-09-25 14:18:03 +0000 |
---|---|---|
committer | thomascube <thomas@roundcube.net> | 2005-09-25 14:18:03 +0000 |
commit | 4e17e6c9dbac8991ee8b302cb2581241247dc8bc (patch) | |
tree | d877546f6bd334b041734498e81f6299e005b01c /program/include |
Initial revision
Diffstat (limited to 'program/include')
-rw-r--r-- | program/include/bugs.inc | 104 | ||||
-rw-r--r-- | program/include/cache.inc | 112 | ||||
-rw-r--r-- | program/include/main.inc | 1020 | ||||
-rw-r--r-- | program/include/rcube_imap.inc | 1117 | ||||
-rw-r--r-- | program/include/rcube_mysql.inc | 186 | ||||
-rw-r--r-- | program/include/rcube_shared.inc | 1417 | ||||
-rw-r--r-- | program/include/session.inc | 154 |
7 files changed, 4110 insertions, 0 deletions
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 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | program/include/bugs.inc | + | | + | This file is part of the BQube Webmail client | + | Copyright (C) 2005, BQube Dev - Switzerland | + | All rights reserved. | + | | + | PURPOSE: | + | Provide error handling and logging functions | + | | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ + + $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 "<b>$program Error in $arg_arr[file] ($arg_arr[line]):</b> "; + print nl2br($arg_arr['message']); + print '<br />'; + 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 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | program/include/cache.inc | + | | + | This file is part of the RoundCube Webmail client | + | Copyright (C) 2005, RoundCube Dev, - Switzerland | + | All rights reserved. | + | | + | PURPOSE: | + | Provide access to the application cache | + | | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ + + $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 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | program/include/main.inc | + | | + | This file is part of the RoundCube Webmail client | + | Copyright (C) 2005, RoundCube Dev, - Switzerland | + | All rights reserved. | + | | + | PURPOSE: | + | Provide basic functions for the webmail package | + | | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ + + $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<hr>\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('/<roundcube:([-_a-z]+)\s+([^>]+)>/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('<img src="%%s"%s />', $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('<input%s disabled />', $attrib_str); + } + + // generate html code for button + if ($btn_content) + { + $attrib_str = create_attrib_string($attrib, $link_attrib); + $out = sprintf('<a%s>%s</a>', $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 <table> tag + $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary')); + + $table = '<table' . $attrib_str . ">\n"; + + // add table title + $table .= "<thead><tr>\n"; + + foreach ($a_show_cols as $col) + $table .= '<td class="'.$col.'">' . rcube_label($col) . "</td>\n"; + + $table .= "</tr></thead>\n<tbody>\n"; + + $c = 0; + while ($sql_result && ($sql_arr = $DB->fetch_assoc($sql_result))) + { + $zebra_class = $c%2 ? 'even' : 'odd'; + + $table .= sprintf('<tr id="rcmrow%d" class="contact '.$zebra_class.'">'."\n", $sql_arr[$id_col]); + + // format each col + foreach ($a_show_cols as $col) + { + $cont = rep_specialchars_output($sql_arr[$col]); + $table .= '<td class="'.$col.'">' . $cont . "</td>\n"; + } + + $table .= "</tr>\n"; + $c++; + } + + // complete message table + $table .= "</tbody></table>\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 <iframe> tag + $attrib_str = ''; + foreach ($allowed_attribs as $a) + if (isset($attrib[$a])) + $attrib_str .= sprintf(' %s="%s"', $a, $attrib[$a]); + + return $attrib_str; + } + + + +function format_date($date, $format=NULL) + { + global $CONFIG, $sess_user_lang; + + if (is_numeric($date)) + $ts = $date; + else + $ts = strtotime($date); + + // convert time to user's timezone + $timestamp = $ts - date('Z', $ts) + ($CONFIG['timezone'] * 3600); + + // get current timestamp in user's timezone + $now = time(); // local time + $now -= (int)date('Z'); // make GMT time + $now += ($CONFIG['timezone'] * 3600); // user's time + + $day_secs = 60*((int)date('H', $now)*60 + (int)date('i', $now)); + $week_secs = 60 * 60 * 24 * 7; + $diff = $now - $timestamp; + + // define daate format depending on current time + if (!$format && $diff < $day_secs) + return sprintf('%s %s', rcube_label('today'), date('H:i', $timestamp)); + else if (!$format && $diff < $week_secs) + $format = $CONFIG['date_short'] ? $CONFIG['date_short'] : 'D H:i'; + else if (!$format) + $format = $CONFIG['date_long'] ? $CONFIG['date_long'] : 'd.m.Y H:i'; + + + // parse format string manually in order to provide localized weekday and month names + // an alternative would be to convert the date() format string to fit with strftime() + $out = ''; + for($i=0; $i<strlen($format); $i++) + { + if ($format{$i}=='\\') // skip escape chars + continue; + + // write char "as-is" + if ($format{$i}==' ' || $format{$i-1}=='\\') + $out .= $format{$i}; + // weekday (short) + else if ($format{$i}=='D') + $out .= rcube_label(strtolower(date('D', $timestamp))); + // weekday long + else if ($format{$i}=='l') + $out .= rcube_label(strtolower(date('l', $timestamp))); + // month name (short) + else if ($format{$i}=='M') + $out .= rcube_label(strtolower(date('M', $timestamp))); + // month name (long) + else if ($format{$i}=='F') + $out .= rcube_label(strtolower(date('F', $timestamp))); + else + $out .= date($format{$i}, $timestamp); + } + + return $out; + } + + +// ************** functions delivering gui objects ************** + + + +function rcmail_message_container($attrib) + { + global $OUTPUT, $JS_OBJECT_NAME; + + if (!$attrib['id']) + $attrib['id'] = 'rcmMessageContainer'; + + // allow the following attributes to be added to the <table> tag + $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id')); + $out = '<div' . $attrib_str . "></div>"; + + $OUTPUT->add_script("$JS_OBJECT_NAME.gui_object('message', '$attrib[id]');"); + + return $out; + } + + +// return code for the webmail login form +function rcmail_login_form($attrib) + { + global $CONFIG, $OUTPUT, $JS_OBJECT_NAME, $SESS_HIDDEN_FIELD; + + $labels = array(); + $labels['user'] = rcube_label('username'); + $labels['pass'] = rcube_label('password'); + $labels['host'] = rcube_label('server'); + + $input_user = new textfield(array('name' => '_user', 'size' => 30)); + $input_pass = new passwordfield(array('name' => '_pass', 'size' => 30)); + $input_action = new hiddenfield(array('name' => '_action', 'value' => 'login')); + + $fields = array(); + $fields['user'] = $input_user->show($_POST['_user']); + $fields['pass'] = $input_pass->show(); + $fields['action'] = $input_action->show(); + + if (is_array($CONFIG['default_host'])) + { + $select_host = new select(array('name' => '_host')); + $select_host->add($CONFIG['default_host']); + $fields['host'] = $select_host->show($_POST['_host']); + } + else if (!strlen($CONFIG['default_host'])) + { + $input_host = new textfield(array('name' => '_host', 'size' => 30)); + $fields['host'] = $input_host->show($_POST['_host']); + } + + $form_name = strlen($attrib['form']) ? $attrib['form'] : 'form'; + $form_start = !strlen($attrib['form']) ? '<form name="form" action="./" method="post">' : ''; + $form_end = !strlen($attrib['form']) ? '</form>' : ''; + + if ($fields['host']) + $form_host = <<<EOF + +</tr><tr> + +<td class="title">$labels[host]</td> +<td>$fields[host]</td> + +EOF; + + $OUTPUT->add_script("$JS_OBJECT_NAME.gui_object('loginform', '$form_name');"); + + $out = <<<EOF +$form_start +$SESS_HIDDEN_FIELD +$fields[action] +<table><tr> + +<td class="title">$labels[user]</td> +<td>$fields[user]</td> + +</tr><tr> + +<td class="title">$labels[pass]</td> +<td>$fields[pass]</td> +$form_host +</tr></table> +$form_end +EOF; + + return $out; + } + + +?>
\ No newline at end of file diff --git a/program/include/rcube_imap.inc b/program/include/rcube_imap.inc new file mode 100644 index 000000000..594dbf40f --- /dev/null +++ b/program/include/rcube_imap.inc @@ -0,0 +1,1117 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | program/include/rcube_imap.inc | + | | + | This file is part of the RoundCube Webmail client | + | Copyright (C) 2005, RoundCube Dev. - Switzerland | + | All rights reserved. | + | | + | PURPOSE: | + | IMAP wrapper that implements the Iloha IMAP Library (IIL) | + | See http://ilohamail.org/ for details | + | | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + + +require_once('lib/imap.inc'); +require_once('lib/mime.inc'); + +// check for Open-SSL support in PHP build +//$ICL_SSL = TRUE; +//$ICL_PORT = 993; + +class rcube_imap + { + var $conn; + var $root_dir = ''; + var $mailbox = 'INBOX'; + var $list_page = 1; + var $page_size = 10; + var $cacheing_enabled = FALSE; + var $default_folders = array('inbox', 'drafts', 'sent', 'junk', 'trash'); + var $cache = array(); + var $cache_changes = array(); + var $uid_id_map = array(); + var $msg_headers = array(); + + + // PHP 5 constructor + function __construct() + { + if (function_exists('rcube_read_cache')) + $this->cacheing_enabled = TRUE; + } + + // PHP 4 compatibility + function rcube_imap() + { + $this->__construct(); + } + + + function iloha_imap($connection='') + { + if ($connection) + { + $a_url = parse_url($connection); + $scheme = $a_url['scheme'] ? $a_url['scheme'] : 'imap'; + $port = $a_url['port'] ? $a_url['port'] : ($scheme=='imaps' ? 993 : 143); + $host = $a_url['host']; + $user = $a_url['user']; + $pass = $a_url['pass']; + + //var_dump($a_url); + + $this->connect($host, $user, $pass, $port); + } + } + + + function connect($host, $user, $pass, $port=143) + { + global $ICL_PORT; + + $ICL_PORT = $port; + $this->conn = iil_Connect($host, $user, $pass); + $this->host = $host; + $this->user = $user; + $this->pass = $pass; + + return $this->conn ? TRUE : FALSE; + } + + + function close() + { + if ($this->conn) + iil_Close($this->conn); + } + + + function set_rootdir($root) + { + if (substr($root, -1, 1)==='/') + $root = substr($root, 0, -1); + + $this->root_dir = $root; + } + + + function set_default_mailboxes($arr) + { + if (is_array($arr)) + { + $this->default_folders = array(); + + // add mailbox names lower case + foreach ($arr as $mbox) + $this->default_folders[] = strtolower($mbox); + + // add inbox if not included + if (!in_array('inbox', $this->default_folders)) + array_unshift($arr, 'inbox'); + } + } + + + function set_mailbox($mbox) + { + $mailbox = $this->_mod_mailbox($mbox); + + if ($this->mailbox == $mailbox) + return; + + $this->mailbox = $mailbox; + + // clear messagecount cache for this mailbox + $this->_clear_messagecount($mailbox); + } + + + function set_page($page) + { + $this->list_page = (int)$page; + } + + + function set_pagesize($size) + { + $this->page_size = (int)$size; + } + + + function get_mailbox_name() + { + return $this->conn ? $this->_mod_mailbox($this->mailbox, 'out') : ''; + } + + + // public method for mailbox listing + // convert mailbox name with root dir first + function list_mailboxes($root='', $filter='*') + { + $a_out = array(); + $a_mboxes = $this->_list_mailboxes($root, $filter); + + foreach ($a_mboxes as $mbox) + { + $name = $this->_mod_mailbox($mbox, 'out'); + if (strlen($name)) + $a_out[] = $name; + } + + // sort mailboxes + $a_out = $this->_sort_mailbox_list($a_out); + + return $a_out; + } + + // private method for mailbox listing + function _list_mailboxes($root='', $filter='*') + { + $a_defaults = $a_out = array(); + + // get cached folder list + $a_mboxes = $this->get_cache('mailboxes'); + if (is_array($a_mboxes)) + return $a_mboxes; + + // retrieve list of folders from IMAP server + $a_folders = iil_C_ListSubscribed($this->conn, $this->_mod_mailbox($root), $filter); + + if (!is_array($a_folders) || !sizeof($a_folders)) + $a_folders = array(); + + // create INBOX if it does not exist + if (!in_array_nocase('INBOX', $a_folders)) + { + $this->create_mailbox('INBOX', TRUE); + array_unshift($a_folders, 'INBOX'); + } + + $a_mailbox_cache = array(); + + // write mailboxlist to cache + $this->update_cache('mailboxes', $a_folders); + + return $a_folders; + } + + + // get message count for a specific mailbox; acceptes modes are: ALL, UNSEEN + function messagecount($mbox='', $mode='ALL', $force=FALSE) + { + $mailbox = $mbox ? $this->_mod_mailbox($mbox) : $this->mailbox; + return $this->_messagecount($mailbox, $mode, $force); + } + + // private method for getting nr of mesages + function _messagecount($mailbox='', $mode='ALL', $force=FALSE) + { + $a_mailbox_cache = FALSE; + $mode = strtoupper($mode); + + if (!$mailbox) + $mailbox = $this->mailbox; + + $a_mailbox_cache = $this->get_cache('messagecount'); + + // return cached value + if (!$force && is_array($a_mailbox_cache[$mailbox]) && isset($a_mailbox_cache[$mailbox][$mode])) + return $a_mailbox_cache[$mailbox][$mode]; + + // get message count and store in cache + if ($mode == 'UNSEEN') + $count = iil_C_CountUnseen($this->conn, $mailbox); + else + $count = iil_C_CountMessages($this->conn, $mailbox); + +//print "/**** get messagecount for $mailbox ($mode): $count ****/\n"; + + if (is_array($a_mailbox_cache[$mailbox])) + $a_mailbox_cache[$mailbox] = array(); + + $a_mailbox_cache[$mailbox][$mode] = (int)$count; + + // write back to cache + $this->update_cache('messagecount', $a_mailbox_cache); + +//var_dump($a_mailbox_cache); + + return (int)$count; + } + + + // public method for listing headers + // convert mailbox name with root dir first + function list_headers($mbox='', $page=NULL, $sort_field='date', $sort_order='DESC') + { + $mailbox = $mbox ? $this->_mod_mailbox($mbox) : $this->mailbox; + return $this->_list_headers($mailbox, $page, $sort_field, $sort_order); + } + + + // private method for listing message header + function _list_headers($mailbox='', $page=NULL, $sort_field='date', $sort_order='DESC') + { + $max = $this->_messagecount($mailbox /*, 'ALL', TRUE*/); + $a_out = array(); + + if (!strlen($mailbox)) + return $a_out; + + + // get cached headers + $a_msg_headers = $this->get_cache($mailbox.'.msg'); + +// print "/**** count = $max; headers = ".sizeof($a_msg_headers)." ****/\n"; + + // retrieve headers from IMAP + if (!is_array($a_msg_headers) || sizeof($a_msg_headers) != $max) + { + $a_header_index = iil_C_FetchHeaders($this->conn, $mailbox, "1:$max"); + $a_msg_headers = array(); + foreach ($a_header_index as $i => $headers) + $a_msg_headers[$headers->uid] = $headers; + +// print "/**** fetch headers ****/\n"; + } + else + $headers_cached = TRUE; + + // sort headers by a specific col + $a_headers = iil_SortHeaders($a_msg_headers, $sort_field, $sort_order); + + // write headers list to cache + if (!$headers_cached) + $this->update_cache($mailbox.'.msg', $a_msg_headers); + + if (is_array($a_headers)) + foreach ($a_headers as $header) + if (!$header->deleted) + $a_out[] = $header; + + // return complete list of messages + if (strtolower($page)=='all') + return $a_out; + + $start_msg = ($this->list_page-1) * $this->page_size; + return array_slice($a_out, $start_msg, $this->page_size); + } + + + // return sorted array of message UIDs + function message_index($mbox='', $sort_field='date', $sort_order='DESC') + { + $mailbox = $mbox ? $this->_mod_mailbox($mbox) : $this->mailbox; + $a_out = array(); + + // get array of message headers + $a_headers = $this->_list_headers($mailbox, 'all', $sort_field, $sort_order); + + if (is_array($a_headers)) + foreach ($a_headers as $header) + $a_out[] = $header->uid; + + return $a_out; + } + + + function sync_header_index($mbox=NULL) + { + + } + + + function search($mbox='', $criteria='ALL') + { + $mailbox = $mbox ? $this->_mod_mailbox($mbox) : $this->mailbox; + $a_messages = iil_C_Search($this->conn, $mailbox, $criteria); + return $a_messages; + } + + + function get_headers($uid, $mbox=NULL) + { + $mailbox = $mbox ? $this->_mod_mailbox($mbox) : $this->mailbox; + + // get cached headers + $a_msg_headers = $this->get_cache($mailbox.'.msg'); + + // return cached header + if ($a_msg_headers[$uid]) + return $a_msg_headers[$uid]; + + $msg_id = $this->_uid2id($uid); + $header = iil_C_FetchHeader($this->conn, $mailbox, $msg_id); + + // write headers cache + $a_msg_headers[$uid] = $header; + $this->update_cache($mailbox.'.msg', $a_msg_headers); + + return $header; + } + + + function get_body($uid, $part=1) + { + if (!($msg_id = $this->_uid2id($uid))) + return FALSE; + + $structure_str = iil_C_FetchStructureString($this->conn, $this->mailbox, $msg_id); + $structure = iml_GetRawStructureArray($structure_str); + $body = iil_C_FetchPartBody($this->conn, $this->mailbox, $msg_id, $part); + + $encoding = iml_GetPartEncodingCode($structure, $part); + + if ($encoding==3) $body = $this->mime_decode($body, 'base64'); + else if ($encoding==4) $body = $this->mime_decode($body, 'quoted-printable'); + + return $body; + } + + + function get_raw_body($uid) + { + if (!($msg_id = $this->_uid2id($uid))) + return FALSE; + + $body = iil_C_FetchPartHeader($this->conn, $this->mailbox, $msg_id, NULL); + $body .= iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, NULL, 1); + + return $body; + } + + + // set message flag to one or several messages + // possible flgs are: SEEN, DELETED, RECENT, ANSWERED, DRAFT + function set_flag($uids, $flag) + { + $flag = strtoupper($flag); + $msg_ids = array(); + if (!is_array($uids)) + $uids = array($uids); + + foreach ($uids as $uid) + $msg_ids[] = $this->_uid2id($uid); + + if ($flag=='UNSEEN') + $result = iil_C_Unseen($this->conn, $this->mailbox, join(',', $msg_ids)); + else + $result = iil_C_Flag($this->conn, $this->mailbox, join(',', $msg_ids), $flag); + + + // reload message headers if cached + $cache_key = $this->mailbox.'.msg'; + if ($result && ($a_cached_headers = $this->get_cache($cache_key))) + { + foreach ($uids as $uid) + { + if (isset($a_cached_headers[$uid])) + { + unset($this->cache[$cache_key][$uid]); + $this->get_headers($uid); + } + } + } + + // set nr of messages that were flaged + $count = sizeof($msg_ids); + + // clear message count cache + if ($result && $flag=='SEEN') + $this->_set_messagecount($this->mailbox, 'UNSEEN', $count*(-1)); + else if ($result && $flag=='UNSEEN') + $this->_set_messagecount($this->mailbox, 'UNSEEN', $count); + else if ($result && $flag=='DELETED') + $this->_set_messagecount($this->mailbox, 'ALL', $count*(-1)); + + return $result; + } + + + // append a mail message (source) to a specific mailbox + function save_message($mbox, $message) + { + $mailbox = $this->_mod_mailbox($mbox); + + // make shure mailbox exists + if (in_array($mailbox, $this->_list_mailboxes())) + $saved = iil_C_Append($this->conn, $mailbox, $message); + + if ($saved) + { + // increase messagecount of the target mailbox + $this->_set_messagecount($mailbox, 'ALL', 1); + } + + return $saved; + } + + + // move a message from one mailbox to another + function move_message($uids, $to_mbox, $from_mbox='') + { + $to_mbox = $this->_mod_mailbox($to_mbox); + $from_mbox = $from_mbox ? $this->_mod_mailbox($from_mbox) : $this->mailbox; + + // make shure mailbox exists + if (!in_array($to_mbox, $this->_list_mailboxes())) + return FALSE; + + // convert the list of uids to array + $a_uids = is_string($uids) ? explode(',', $uids) : (is_array($uids) ? $uids : NULL); + + // exit if no message uids are specified + if (!is_array($a_uids)) + return false; + + // convert uids to message ids + $a_mids = array(); + foreach ($a_uids as $uid) + $a_mids[] = $this->_uid2id($uid, $from_mbox); + + $moved = iil_C_Move($this->conn, join(',', $a_mids), $from_mbox, $to_mbox); + + // send expunge command in order to have the moved message + // really deleted from the source mailbox + if ($moved) + { + $this->expunge($from_mbox, FALSE); + $this->clear_cache($to_mbox.'.msg'); + $this->_clear_messagecount($from_mbox); + $this->_clear_messagecount($to_mbox); + } + + // update cached message headers + $cache_key = $from_mbox.'.msg'; + if ($moved && ($a_cached_headers = $this->get_cache($cache_key))) + { + foreach ($a_uids as $uid) + unset($a_cached_headers[$uid]); + + $this->update_cache($cache_key, $a_cached_headers); + } + + return $moved; + } + + + // mark messages as deleted and expunge mailbox + function delete_message($uids, $mbox='') + { + $mailbox = $mbox ? $this->_mod_mailbox($mbox) : $this->mailbox; + + // convert the list of uids to array + $a_uids = is_string($uids) ? explode(',', $uids) : (is_array($uids) ? $uids : NULL); + + // exit if no message uids are specified + if (!is_array($a_uids)) + return false; + + + // convert uids to message ids + $a_mids = array(); + foreach ($a_uids as $uid) + $a_mids[] = $this->_uid2id($uid, $mailbox); + + $deleted = iil_C_Delete($this->conn, $mailbox, join(',', $a_mids)); + + // send expunge command in order to have the deleted message + // really deleted from the mailbox + if ($deleted) + { + $this->expunge($mailbox, FALSE); + $this->_clear_messagecount($mailbox); + } + + // remove deleted messages from cache + if ($deleted && ($a_cached_headers = $this->get_cache($mailbox.'.msg'))) + { + foreach ($a_uids as $uid) + unset($a_cached_headers[$uid]); + + $this->update_cache($mailbox.'.msg', $a_cached_headers); + } + + return $deleted; + + } + + + // send IMAP expunge command and clear cache + function expunge($mbox='', $clear_cache=TRUE) + { + $mailbox = $mbox ? $this->_mod_mailbox($mbox) : $this->mailbox; + + $result = iil_C_Expunge($this->conn, $mailbox); + + if ($result>=0 && $clear_cache) + { + $this->clear_cache($mailbox.'.msg'); + $this->_clear_messagecount($mailbox); + } + + return $result; + } + + + + /* -------------------------------- + * folder managment + * --------------------------------*/ + + + // return an array with all folders available in IMAP server + function list_unsubscribed($root='') + { + static $sa_unsubscribed; + + if (is_array($sa_unsubscribed)) + return $sa_unsubscribed; + + // retrieve list of folders from IMAP server + $a_mboxes = iil_C_ListMailboxes($this->conn, $this->_mod_mailbox($root), '*'); + + // modify names with root dir + foreach ($a_mboxes as $mbox) + { + $name = $this->_mod_mailbox($mbox, 'out'); + if (strlen($name)) + $a_folders[] = $name; + } + + // filter folders and sort them + $sa_unsubscribed = $this->_sort_mailbox_list($a_folders); + return $sa_unsubscribed; + } + + + // subscribe to a specific mailbox(es) + function subscribe($mbox, $mode='subscribe') + { + if (is_array($mbox)) + $a_mboxes = $mbox; + else if (is_string($mbox) && strlen($mbox)) + $a_mboxes = explode(',', $mbox); + + // let this common function do the main work + return $this->_change_subscription($a_mboxes, 'subscribe'); + } + + + // unsubscribe mailboxes + function unsubscribe($mbox) + { + if (is_array($mbox)) + $a_mboxes = $mbox; + else if (is_string($mbox) && strlen($mbox)) + $a_mboxes = explode(',', $mbox); + + // let this common function do the main work + return $this->_change_subscription($a_mboxes, 'unsubscribe'); + } + + + // create a new mailbox on the server and register it in local cache + function create_mailbox($name, $subscribe=FALSE) + { + $result = FALSE; + $abs_name = $this->_mod_mailbox($name); + $a_mailbox_cache = $this->get_cache('mailboxes'); + + if (strlen($abs_name) && (!is_array($a_mailbox_cache) || !in_array($abs_name, $a_mailbox_cache))) + $result = iil_C_CreateFolder($this->conn, $abs_name); + + // update mailboxlist cache + if ($result && $subscribe) + $this->subscribe($name); + + return $result; + } + + + // set a new name to an existing mailbox + function rename_mailbox($mbox, $new_name) + { + // not implemented yet + } + + + // remove mailboxes from server + function delete_mailbox($mbox) + { + $deleted = FALSE; + + if (is_array($mbox)) + $a_mboxes = $mbox; + else if (is_string($mbox) && strlen($mbox)) + $a_mboxes = explode(',', $mbox); + + if (is_array($a_mboxes)) + foreach ($a_mboxes as $mbox) + { + $mailbox = $this->_mod_mailbox($mbox); + + // unsubscribe mailbox before deleting + iil_C_UnSubscribe($this->conn, $mailbox); + + // send delete command to server + $result = iil_C_DeleteFolder($this->conn, $mailbox); + if ($result>=0) + $deleted = TRUE; + } + + // clear mailboxlist cache + if ($deleted) + $this->clear_cache('mailboxes'); + + return $updated; + } + + + + + /* -------------------------------- + * internal cacheing functions + * --------------------------------*/ + + + function get_cache($key) + { + // read cache + if (!isset($this->cache[$key]) && $this->cacheing_enabled) + { + $cache_data = rcube_read_cache('IMAP.'.$key); + $this->cache[$key] = strlen($cache_data) ? unserialize($cache_data) : FALSE; + } + + return $this->cache[$key]; + } + + + function update_cache($key, $data) + { + $this->cache[$key] = $data; + $this->cache_changed = TRUE; + $this->cache_changes[$key] = TRUE; + } + + + function write_cache() + { + if ($this->cacheing_enabled && $this->cache_changed) + { + foreach ($this->cache as $key => $data) + { + if ($this->cache_changes[$key]) + rcube_write_cache('IMAP.'.$key, serialize($data)); + } + } + } + + + function clear_cache($key=NULL) + { + if ($key===NULL) + { + foreach ($this->cache as $key => $data) + rcube_clear_cache('IMAP.'.$key); + + $this->cache = array(); + $this->cache_changed = FALSE; + $this->cache_changes = array(); + } + else + { + rcube_clear_cache('IMAP.'.$key); + $this->cache_changes[$key] = FALSE; + unset($this->cache[$key]); + } + } + + + + /* -------------------------------- + * encoding/decoding functions + * --------------------------------*/ + + + function decode_address_list($input, $max=NULL) + { + $a = $this->_parse_address_list($input); + $out = array(); + + if (!is_array($a)) + return $out; + + $c = count($a); + $j = 0; + + foreach ($a as $val) + { + $j++; + $address = $val['address']; + $name = preg_replace(array('/^[\'"]/', '/[\'"]$/'), '', trim($val['name'])); + $string = $name!==$address ? sprintf('%s <%s>', strpos($name, ',')!==FALSE ? '"'.$name.'"' : $name, $address) : $address; + + $out[$j] = array('name' => $name, + 'mailto' => $address, + 'string' => $string); + + if ($max && $j==$max) + break; + } + + return $out; + } + + + function decode_header($input) + { + $out = ''; + + $pos = strpos($input, '=?'); + if ($pos !== false) + { + $out = substr($input, 0, $pos); + + $end_cs_pos = strpos($input, "?", $pos+2); + $end_en_pos = strpos($input, "?", $end_cs_pos+1); + $end_pos = strpos($input, "?=", $end_en_pos+1); + + $encstr = substr($input, $pos+2, ($end_pos-$pos-2)); + $rest = substr($input, $end_pos+2); + + $out .= $this->decode_mime_string($encstr); + $out .= $this->decode_header($rest); + + return $out; + } + else + return $input; + } + + + function decode_mime_string($str) + { + $a = explode('?', $str); + $count = count($a); + + // should be in format "charset?encoding?base64_string" + if ($count >= 3) + { + for ($i=2; $i<$count; $i++) + $rest.=$a[$i]; + + if (($a[1]=="B")||($a[1]=="b")) + $rest = base64_decode($rest); + else if (($a[1]=="Q")||($a[1]=="q")) + { + $rest = str_replace("_", " ", $rest); + $rest = quoted_printable_decode($rest); + } + + return decode_specialchars($rest, $a[0]); + } + else + return $str; //we dont' know what to do with this + } + + + function mime_decode($input, $encoding='7bit') + { + switch (strtolower($encoding)) + { + case '7bit': + return $input; + break; + + case 'quoted-printable': + return quoted_printable_decode($input); + break; + + case 'base64': + return base64_decode($input); + break; + + default: + return $input; + } + } + + + function mime_encode($input, $encoding='7bit') + { + switch ($encoding) + { + case 'quoted-printable': + return quoted_printable_encode($input); + break; + + case 'base64': + return base64_encode($input); + break; + + default: + return $input; + } + } + + + // convert body chars according to the ctype_parameters + function charset_decode($body, $ctype_param) + { + if (is_array($ctype_param) && strlen($ctype_param['charset'])) + return decode_specialchars($body, $ctype_param['charset']); + + return $body; + } + + + /* -------------------------------- + * private methods + * --------------------------------*/ + + + function _mod_mailbox($mbox, $mode='in') + { + if ($this->root_dir && $mode=='in') + $mbox = $this->root_dir.'/'.$mbox; + else if ($this->root_dir && $mode=='out') + $mbox = substr($mbox, strlen($this->root_dir)+1); + + return $mbox; + } + + + // sort mailboxes first by default folders and then in alphabethical order + function _sort_mailbox_list($a_folders) + { + $a_out = $a_defaults = array(); + + // find default folders and skip folders starting with '.' + foreach($a_folders as $i => $folder) + { + if ($folder{0}=='.') + continue; + + if (($p = array_search(strtolower($folder), $this->default_folders))!==FALSE) + $a_defaults[$p] = $folder; + else + $a_out[] = $folder; + } + + sort($a_out); + ksort($a_defaults); + + return array_merge($a_defaults, $a_out); + } + + + function _uid2id($uid, $mbox=NULL) + { + if (!$mbox) + $mbox = $this->mailbox; + + if (!isset($this->uid_id_map[$mbox][$uid])) + $this->uid_id_map[$mbox][$uid] = iil_C_UID2ID($this->conn, $mbox, $uid); + + return $this->uid_id_map[$mbox][$uid]; + } + + + // subscribe/unsubscribe a list of mailboxes and update local cache + function _change_subscription($a_mboxes, $mode) + { + $updated = FALSE; + + if (is_array($a_mboxes)) + foreach ($a_mboxes as $i => $mbox) + { + $mailbox = $this->_mod_mailbox($mbox); + $a_mboxes[$i] = $mailbox; + + if ($mode=='subscribe') + $result = iil_C_Subscribe($this->conn, $mailbox); + else if ($mode=='unsubscribe') + $result = iil_C_UnSubscribe($this->conn, $mailbox); + + if ($result>=0) + $updated = TRUE; + } + + // get cached mailbox list + if ($updated) + { + $a_mailbox_cache = $this->get_cache('mailboxes'); + if (!is_array($a_mailbox_cache)) + return $updated; + + // modify cached list + if ($mode=='subscribe') + $a_mailbox_cache = array_merge($a_mailbox_cache, $a_mboxes); + else if ($mode=='unsubscribe') + $a_mailbox_cache = array_diff($a_mailbox_cache, $a_mboxes); + + // write mailboxlist to cache + $this->update_cache('mailboxes', $this->_sort_mailbox_list($a_mailbox_cache)); + } + + return $updated; + } + + + // increde/decrese messagecount for a specific mailbox + function _set_messagecount($mbox, $mode, $increment) + { + $a_mailbox_cache = FALSE; + $mailbox = $mbox ? $mbox : $this->mailbox; + $mode = strtoupper($mode); + + $a_mailbox_cache = $this->get_cache('messagecount'); + + if (!is_array($a_mailbox_cache[$mailbox]) || !isset($a_mailbox_cache[$mailbox][$mode]) || !is_numeric($increment)) + return FALSE; + + // add incremental value to messagecount + $a_mailbox_cache[$mailbox][$mode] += $increment; + + // write back to cache + $this->update_cache('messagecount', $a_mailbox_cache); + + return TRUE; + } + + + // remove messagecount of a specific mailbox from cache + function _clear_messagecount($mbox='') + { + $a_mailbox_cache = FALSE; + $mailbox = $mbox ? $mbox : $this->mailbox; + + $a_mailbox_cache = $this->get_cache('messagecount'); + + if (is_array($a_mailbox_cache[$mailbox])) + { + unset($a_mailbox_cache[$mailbox]); + $this->update_cache('messagecount', $a_mailbox_cache); + } + } + + + function _parse_address_list($str) + { + $a = $this->_explode_quoted_string(',', $str); + $result = array(); + + foreach ($a as $key => $val) + { + $val = str_replace("\"<", "\" <", $val); + $sub_a = $this->_explode_quoted_string(' ', $val); + + foreach ($sub_a as $k => $v) + { + if ((strpos($v, '@') > 0) && (strpos($v, '.') > 0)) + $result[$key]['address'] = str_replace('<', '', str_replace('>', '', $v)); + else + $result[$key]['name'] .= (empty($result[$key]['name'])?'':' ').str_replace("\"",'',stripslashes($v)); + } + + if (empty($result[$key]['name'])) + $result[$key]['name'] = $result[$key]['address']; + + $result[$key]['name'] = $this->decode_header($result[$key]['name']); + } + + return $result; + } + + + function _explode_quoted_string($delimiter, $string) + { + $quotes = explode("\"", $string); + foreach ($quotes as $key => $val) + if (($key % 2) == 1) + $quotes[$key] = str_replace($delimiter, "_!@!_", $quotes[$key]); + + $string = implode("\"", $quotes); + + $result = explode($delimiter, $string); + foreach ($result as $key => $val) + $result[$key] = str_replace("_!@!_", $delimiter, $result[$key]); + + return $result; + } + } + + + + + +function quoted_printable_encode($input="", $line_max=76, $space_conv=false) + { + $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); + $lines = preg_split("/(?:\r\n|\r|\n)/", $input); + $eol = "\r\n"; + $escape = "="; + $output = ""; + + while( list(, $line) = each($lines)) + { + //$line = rtrim($line); // remove trailing white space -> no =20\r\n necessary + $linlen = strlen($line); + $newline = ""; + for($i = 0; $i < $linlen; $i++) + { + $c = substr( $line, $i, 1 ); + $dec = ord( $c ); + if ( ( $i == 0 ) && ( $dec == 46 ) ) // convert first point in the line into =2E + { + $c = "=2E"; + } + if ( $dec == 32 ) + { + if ( $i == ( $linlen - 1 ) ) // convert space at eol only + { + $c = "=20"; + } + else if ( $space_conv ) + { + $c = "=20"; + } + } + else if ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) // always encode "\t", which is *not* required + { + $h2 = floor($dec/16); + $h1 = floor($dec%16); + $c = $escape.$hex["$h2"].$hex["$h1"]; + } + + if ( (strlen($newline) + strlen($c)) >= $line_max ) // CRLF is not counted + { + $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay + $newline = ""; + // check if newline first character will be point or not + if ( $dec == 46 ) + { + $c = "=2E"; + } + } + $newline .= $c; + } // end of for + $output .= $newline.$eol; + } // end of while + + return trim($output); + } + +?> diff --git a/program/include/rcube_mysql.inc b/program/include/rcube_mysql.inc new file mode 100644 index 000000000..bcffe5e2b --- /dev/null +++ b/program/include/rcube_mysql.inc @@ -0,0 +1,186 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | program/include/rcube_mysql.inc | + | | + | This file is part of the RoundCube Webmail client | + | Copyright (C) 2005, RoundCube Dev. - Switzerland | + | All rights reserved. | + | | + | PURPOSE: | + | MySQL wrapper class that implements PHP MySQL functions | + | See http://www.php.net/manual/en/ref.mysql.php | + | | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + + +class rcube_mysql + { + var $db_link; + var $db_host = 'localhost'; + var $db_name = ''; + var $db_user = ''; + var $db_pass = ''; + var $a_query_results = array('dummy'); + var $last_res_id = 0; + + + // PHP 5 constructor + function __construct($db_name='', $user='', $pass='', $host='localhost') + { + $this->db_host = $host; + $this->db_name = $db_name; + $this->db_user = $user; + $this->db_pass = $pass; + } + + // PHP 4 compatibility + function rcube_mysql($db_name='', $user='', $pass='', $host='localhost') + { + $this->__construct($db_name, $user, $pass, $host); + } + + + function connect() + { + $this->db_link = mysql_connect($this->db_host, $this->db_user, $this->db_pass); + + if (!$this->db_link) + { + raise_error(array('code' => 500, + 'type' => 'mysql', + 'line' => __LINE__, + 'file' => __FILE__, + 'message' => "Can't connect to database"), TRUE, FALSE); + return FALSE; + } + + return TRUE; + } + + + function select_db($name) + { + $this->db_name = $name; + + if ($this->db_link) + mysql_select_db($name, $this->db_link); + } + + + function query($query) + { + // establish a connection + if (!$this->db_link) + { + if (!$this->connect()) + return FALSE; + } + + $sql_result = mysql_db_query($this->db_name, $query, $this->db_link); + return $this->_add_result($sql_result, $query); + } + + + function num_rows($res_id=NULL) + { + if (!$this->db_link) + return FALSE; + + $sql_result = $this->_get_result($res_id); + + if ($sql_result) + return mysql_num_rows($sql_result); + else + return FALSE; + } + + + function affected_rows() + { + if (!$this->db_link) + return FALSE; + + return mysql_affected_rows($this->db_link); + } + + + function insert_id() + { + if (!$this->db_link) + return FALSE; + + return mysql_insert_id($this->db_link); + } + + + function fetch_assoc($res_id=NULL) + { + $sql_result = $this->_get_result($res_id); + + if ($sql_result) + return mysql_fetch_assoc($sql_result); + else + return FALSE; + } + + + function seek($res_id=NULL, $row=0) + { + $sql_result = $this->_get_result($res_id); + + if ($sql_result) + return mysql_data_seek($sql_result, $row); + else + return FALSE; + } + + + + function _add_result($res, $query) + { + // sql error occured + if ($res===FALSE) + { + $sql_error = mysql_error($this->db_link); + raise_error(array('code' => 500, + 'type' => 'mysql', + 'line' => __LINE__, + 'file' => __FILE__, + 'message' => $sql_error."; QUERY: ".preg_replace('/[\r\n]+\s*/', ' ', $query)), TRUE, FALSE); + + return FALSE; + } + else + { + $res_id = sizeof($this->a_query_results); + $this->a_query_results[$res_id] = $res; + $this->last_res_id = $res_id; + + return $res_id; + } + } + + + function _get_result($res_id) + { + if ($res_id===NULL) + $res_id = $this->last_res_id; + + if ($res_id && isset($this->a_query_results[$res_id])) + return $this->a_query_results[$res_id]; + else + return FALSE; + } + + } + + +?>
\ No newline at end of file diff --git a/program/include/rcube_shared.inc b/program/include/rcube_shared.inc new file mode 100644 index 000000000..2c0b0517b --- /dev/null +++ b/program/include/rcube_shared.inc @@ -0,0 +1,1417 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | rcube_shared.inc | + | | + | This file is part of the RoundCube PHP suite | + | Copyright (C) 2005, RoundCube Dev. - Switzerland | + | All rights reserved. | + | | + | CONTENTS: | + | Shared functions and classes used in PHP projects | + | | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + + +// ********* round cube schared classes ********* + +class rcube_html_page + { + var $css; + + var $scripts_path = ''; + var $script_files = array(); + var $scripts = array(); + + var $script_tag_file = "<script type=\"text/javascript\" src=\"%s%s\"></script>\n"; + var $script_tag = "<script type=\"text/javascript\">\n<!--\n%s\n\n//-->\n</script>\n"; + + var $title = ''; + var $header = ''; + var $footer = ''; + var $body = ''; + var $body_attrib = array(); + var $meta_tags = array(); + + + // PHP 5 constructor + function __construct() + { + $this->css = new rcube_css(); + } + + // PHP 4 compatibility + function rcube_html_page() + { + $this->__construct(); + } + + + function include_script($file, $position='head') + { + static $sa_files = array(); + + if (in_array($file, $sa_files)) + return; + + if (!is_array($this->script_files[$position])) + $this->script_files[$position] = array(); + + $this->script_files[$position][] = $file; + } + + + function add_script($script, $position='head') + { + if (!isset($this->scripts[$position])) + $this->scripts[$position] = ''; + + $this->scripts[$position] .= "\n$script"; + } + + + function set_title() + { + + } + + + function write($templ='', $base_path='') + { + $output = trim($templ); + + // set default page title + if (!strlen($this->title)) + $this->title = 'RoundCube|Mail'; + + // replace specialchars in content + $__page_title = rep_specialchars_output($this->title, 'html', 'show', FALSE); + $__page_header = $__page_body = $__page_footer = ''; + + + // definition of the code to be placed in the document header and footer + if (is_array($this->script_files['head'])) + foreach ($this->script_files['head'] as $file) + $__page_header .= sprintf($this->script_tag_file, $this->scripts_path, $file); + + if (strlen($this->scripts['head'])) + $__page_header .= sprintf($this->script_tag, $this->scripts['head']); + + if (is_array($this->script_files['foot'])) + foreach ($this->script_files['foot'] as $file) + $__page_footer .= sprintf($this->script_tag_file, $this->scripts_path, $file); + + if (strlen($this->scripts['foot'])) + $__page_footer .= sprintf($this->script_tag, $this->scripts['foot']); + + + $__page_header .= $this->css->show(); + + + // find page header + if($hpos = strpos(strtolower($output), '</head>')) + $__page_header .= "\n"; + else + { + if (!is_numeric($hpos)) + $hpos = strpos(strtolower($output), '<body'); + if (!is_numeric($hpos) && ($hpos = strpos(strtolower($output), '<html'))) + { + while($output[$hpos]!='>') + $hpos++; + $hpos++; + } + + $__page_header = "<head>\n<title>$__page_title</title>\n$__page_header\n</head>\n"; + } + + // add page hader + if($hpos) + $output = substr($output,0,$hpos) . $__page_header . substr($output,$hpos,strlen($output)); + else + $output = $__page_header . $output; + + + // find page body + if($bpos = strpos(strtolower($output), '<body')) + { + while($output[$bpos]!='>') $bpos++; + $bpos++; + } + else + $bpos = strpos(strtolower($output), '</head>')+7; + + // add page body + if($bpos && $__page_body) + $output = substr($output,0,$bpos) . "\n$__page_body\n" . substr($output,$bpos,strlen($output)); + + + // find and add page footer + if(($fpos = strpos(strtolower($output), '</body>')) || ($fpos = strpos(strtolower($output), '</html>'))) + $output = substr($output,0,$fpos) . "$__page_footer\n" . substr($output,$fpos,strlen($output)); + else + $output .= "\n$__page_footer"; + + + // reset those global vars + $__page_header = $__page_footer = ''; + + + // correct absolute pathes in images and other tags + $output = preg_replace('/(src|href|background)=(["\']?)(\/[a-z0-9_\-]+)/Ui', "\\1=\\2$base_path\\3", $output); + + print $output; + } + + + function _parse($templ) + { + + } + } + + + + +class rcube_css + { + var $css_data = array(); + + var $css_groups = array(); + + var $include_files = array(); + + var $grouped_output = TRUE; + + var $content_type = 'text/css'; + + var $base_path = ''; + + var $indent_chars = "\t"; + + + // add or overwrite a css definition + // either pass porperty and value as separate arguments + // or provide an associative array as second argument + function set_style($selector, $property, $value='') + { + $a_elements = $this->_parse_selectors($selector); + foreach ($a_elements as $element) + { + if (!is_array($property)) + $property = array($property => $value); + + foreach ($property as $name => $value) + $this->css_data[$element][strtolower($name)] = $value; + } + + // clear goups array + $this->css_groups = array(); + } + + + // unset a style property + function remove_style($selector, $property) + { + if (!is_array($property)) + $property = array($property); + + foreach ($property as $key) + unset($this->css_data[$selector][strtolower($key)]); + + // clear goups array + $this->css_groups = array(); + } + + + // define base path for external css files + function set_basepath($path) + { + $this->base_path = preg_replace('/\/$/', '', $path); + } + + + // enable/disable grouped output + function set_grouped_output($grouped) + { + $this->grouped_output = $grouped; + } + + + // add a css file as external source + function include_file($filename, $media='') + { + // include multiple files + if (is_array($filename)) + { + foreach ($filename as $file) + $this->include_file($file, $media); + } + // add single file + else if (!in_array($filename, $this->include_files)) + $this->include_files[] = array('file' => $filename, + 'media' => $media); + } + + + // parse css code + function import_string($str) + { + $ret = FALSE; + if (strlen($str)) + $ret = $this->_parse($str); + + return $ret; + } + + + // open and parse a css file + function import_file($file) + { + $ret = FALSE; + + if (!is_file($file)) + return $ret; + + // for php version >= 4.3.0 + if (function_exists('file_get_contents')) + $ret = $this->_parse(file_get_contents($file)); + + // for order php versions + else if ($fp = fopen($file, 'r')) + { + $ret = $this->_parse(fread($fp, filesize($file))); + fclose($fp); + } + + return $ret; + } + + + // copy all properties inherited from superior styles to a specific selector + function copy_inherited_styles($selector) + { + // get inherited props from body and tag/class selectors + $css_props = $this->_get_inherited_styles($selector); + + // write modified props back and clear goups array + if (sizeof($css_props)) + { + $this->css_data[$selector] = $css_props; + $this->css_groups = array(); + } + } + + + // return css definition for embedding in HTML + function show() + { + $out = ''; + + // include external css files + if (sizeof($this->include_files)) + foreach ($this->include_files as $file_arr) + $out .= sprintf('<link rel="stylesheet" type="%s" href="%s"%s>'."\n", + $this->content_type, + $this->_get_file_path($file_arr['file']), + $file_arr['media'] ? ' media="'.$file_arr['media'].'"' : ''); + + + // compose css string + if (sizeof($this->css_data)) + $out .= sprintf("<style type=\"%s\">\n<!--\n\n%s-->\n</style>", + $this->content_type, + $this->to_string()); + + + return $out; + } + + + // return valid css code of the current styles grid + function to_string($selector=NULL) + { + // return code for a single selector + if ($selector) + { + $indent_str = $this->indent_chars; + $this->indent_chars = ''; + + $prop_arr = $this->to_array($selector); + $out = $this->_style2string($prop_arr, TRUE); + + $this->indent_chars = $indent_str; + } + + // compose css code for complete data grid + else + { + $out = ''; + $css_data = $this->to_array(); + + foreach ($css_data as $key => $prop_arr) + $out .= sprintf("%s {\n%s}\n\n", + $key, + $this->_style2string($prop_arr, TRUE)); + } + + return $out; + } + + + // return a single-line string of a css definition + function to_inline($selector) + { + if ($this->css_data[$selector]) + return str_replace('"', '\\"', $this->_style2string($this->css_data[$selector], FALSE)); + } + + + // return an associative array with selector(s) as key and styles array as value + function to_array($selector=NULL) + { + if (!$selector && $this->grouped_output) + { + // build groups if desired + if (!sizeof($this->css_groups)) + $this->_build_groups(); + + // modify group array to get an array(selector => properties) + $out_arr = array(); + foreach ($this->css_groups as $group_arr) + { + $key = join(', ', $group_arr['selectors']); + $out_arr[$key] = $group_arr['properties']; + } + } + else + $out_arr = $this->css_data; + + return $selector ? $out_arr[$selector] : $out_arr; + } + + + // create a css file + function to_file($filepath) + { + if ($fp = fopen($filepath, 'w')) + { + fwrite($fp, $this->to_string()); + fclose($fp); + return TRUE; + } + + return FALSE; + } + + + // alias method for import_string() [DEPRECATED] + function add($str) + { + $this->import_string($str); + } + + // alias method for to_string() [DEPRECATED] + function get() + { + return $this->to_string(); + } + + + + // ******** private methods ******** + + + // parse a string and add styles to internal data grid + function _parse($str) + { + // remove comments + $str = preg_replace("/\/\*(.*)?\*\//Usi", '', $str); + + // parse style definitions + if (!preg_match_all ('/([a-z0-9\.#*:_][a-z0-9\.\-_#:*,\[\]\(\)\s\"\'\+\|>~=]+)\s*\{([^\}]*)\}/ims', $str, $matches, PREG_SET_ORDER)) + return FALSE; + + + foreach ($matches as $match_arr) + { + // split selectors into array + $a_keys = $this->_parse_selectors(trim($match_arr[1])); + + // parse each property of an element + $codes = explode(";", trim($match_arr[2])); + foreach ($codes as $code) + { + if (strlen(trim($code))>0) + { + // find the property and the value + if (!($sep = strpos($code, ':'))) + continue; + + $property = strtolower(trim(substr($code, 0, $sep))); + $value = trim(substr($code, $sep+1)); + + // add the property to the object array + foreach ($a_keys as $key) + $this->css_data[$key][$property] = $value; + } + } + } + + // clear goups array + if (sizeof($matches)) + { + $this->css_groups = array(); + return TRUE; + } + + return FALSE; + } + + + // split selector group + function _parse_selectors($selector) + { + // trim selector and remove multiple spaces + $selector = preg_replace('/\s+/', ' ', trim($selector)); + + if (strpos($selector, ',')) + return preg_split('/[\t\s\n\r]*,[\t\s\n\r]*/mi', $selector); + else + return array($selector); + } + + + // compare identical styles and make groups + function _build_groups() + { + // clear group array + $this->css_groups = array(); + $string_group_map = array(); + + // bulild css string for each selector and check if the same is already defines + foreach ($this->css_data as $selector => $prop_arr) + { + // make shure to compare props in the same order + ksort($prop_arr); + $compare_str = preg_replace('/[\s\t]+/', '', $this->_style2string($prop_arr, FALSE)); + + // add selector to extisting group + if (isset($string_group_map[$compare_str])) + { + $group_index = $string_group_map[$compare_str]; + $this->css_groups[$group_index]['selectors'][] = $selector; + } + + // create new group + else + { + $i = sizeof($this->css_groups); + $string_group_map[$compare_str] = $i; + $this->css_groups[$i] = array('selectors' => array($selector), + 'properties' => $this->css_data[$selector]); + } + } + } + + + // convert the prop array into a valid css definition + function _style2string($prop_arr, $multiline=TRUE) + { + $out = ''; + $delm = $multiline ? "\n" : ''; + $spacer = $multiline ? ' ' : ''; + $indent = $multiline ? $this->indent_chars : ''; + + if (is_array($prop_arr)) + foreach ($prop_arr as $prop => $value) + if (strlen($value)) + $out .= sprintf('%s%s:%s%s;%s', + $indent, + $prop, + $spacer, + $value, + $delm); + + return $out; + } + + + // copy all properties inherited from superior styles to a specific selector + function _get_inherited_styles($selector, $loop=FALSE) + { + $css_props = $this->css_data[$selector] ? $this->css_data[$selector] : array(); + + // get styles from tag selector + if (preg_match('/(([a-z0-9]*)(\.[^\s]+)?)$/i', $selector, $regs)) + { + $sel = $regs[1]; + $tagname = $regs[2]; + $class = $regs[3]; + + if ($sel && is_array($this->css_data[$sel])) + $css_props = $this->_merge_styles($this->css_data[$sel], $css_props); + + if ($class && is_array($this->css_data[$class])) + $css_props = $this->_merge_styles($this->css_data[$class], $css_props); + + if ($tagname && is_array($this->css_data[$tagname])) + $css_props = $this->_merge_styles($this->css_data[$tagname], $css_props); + } + + // analyse inheritance + if (strpos($selector, ' ')) + { + $a_hier = split(' ', $selector); + if (sizeof($a_hier)>1) + { + array_pop($a_hier); + $base_selector = join(' ', $a_hier); + + // call this method recursively + $new_props = $this->_get_inherited_styles($base_selector, TRUE); + $css_props = $this->_merge_styles($new_props, $css_props); + } + } + + // get body style + if (!$loop && is_array($this->css_data['body'])) + $css_props = $this->_merge_styles($this->css_data['body'], $css_props); + + return $css_props; + } + + + // merge two arrays with style properties together like a browser would do + function _merge_styles($one, $two) + { + // these properties are additive + foreach (array('text-decoration') as $prop) + if ($one[$prop] && $two[$prop]) + { + // if value contains 'none' it's ignored + if (strstr($one[$prop], 'none')) + continue; + else if (strstr($two[$prop], 'none')) + unset($two[$prop]); + + $a_values_one = split(' ', $one[$prop]); + $a_values_two = split(' ', $two[$prop]); + $two[$prop] = join(' ', array_unique(array_merge($a_values_one, $a_values_two))); + } + + return array_merge($one, $two); + } + + + // resolve file path + function _get_file_path($file) + { + if (!$this->base_path && $GLOBALS['CSS_PATH']) + $this->set_basepath($GLOBALS['CSS_PATH']); + + $base = ($file{0}=='/' || $file{0}=='.' || substr($file, 0, 7)=='http://') ? '' : + ($this->base_path ? $this->base_path.'/' : ''); + return $base.$file; + } + + } + + + +class base_form_element + { + var $uppertags = FALSE; + var $upperattribs = FALSE; + var $upperprops = FALSE; + var $newline = FALSE; + + var $attrib = array(); + + + // create string with attributes + function create_attrib_string($tagname='') + { + if (!sizeof($this->attrib)) + return ''; + + if ($this->name!='') + $this->attrib['name'] = $this->name; + + $attrib_arr = array(); + foreach ($this->attrib as $key => $value) + { + // don't output some internally used attributes + if (in_array($key, array('form', 'quicksearch'))) + continue; + + // skip if size if not numeric + if (($key=='size' && !is_numeric($value))) + continue; + + // skip empty eventhandlers + if ((strpos($key,'on')===0 && $value=='')) + continue; + + // encode textarea content + if ($key=='value') + $value = rep_specialchars_output($value, 'html', 'replace', FALSE); + + // attributes with no value + if (in_array($key, array('checked', 'multiple', 'disabled', 'selected'))) + { + if ($value) + $attrib_arr[] = $key; + } + // don't convert size of value attribute + else if ($key=='value') + $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $value, 'value'); + + // regular tag attributes + else + $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $this->_conv_case($value, 'value')); + } + + return sizeof($attrib_arr) ? ' '.implode(' ', $attrib_arr) : ''; + } + + + // convert tags and attributes to upper-/lowercase + // $type can either be "tag" or "attrib" + function _conv_case($str, $type='attrib') + { + if ($type == 'tag') + return $this->uppertags ? strtoupper($str) : strtolower($str); + else if ($type == 'attrib') + return $this->upperattribs ? strtoupper($str) : strtolower($str); + else if ($type == 'value') + return $this->upperprops ? strtoupper($str) : strtolower($str); + } + } + + +class input_field extends base_form_element + { + var $type = 'text'; + + // PHP 5 constructor + function __construct($attrib=NULL) + { + if (is_array($attrib)) + $this->attrib = $attrib; + + if ($attrib['type']) + $this->type = $attrib['type']; + + if ($attrib['newline']) + $this->newline = TRUE; + } + + // PHP 4 compatibility + function input_field($attrib=array()) + { + $this->__construct($attrib); + } + + // compose input tag + function show($value=NULL, $attrib=NULL) + { + // overwrite object attributes + if (is_array($attrib)) + $this->attrib = array_merge($this->attrib, $attrib); + + // set value attribute + if ($value!==NULL) + $this->attrib['value'] = $value; + + $this->attrib['type'] = $this->type; + + // return final tag + return sprintf('<%s%s />%s', + $this->_conv_case('input', 'tag'), + $this->create_attrib_string(), + ($this->newline ? "\n" : "")); + } + } + + +class textfield extends input_field + { + var $type = 'text'; + } + +class passwordfield extends input_field + { + var $type = 'password'; + } + +class radiobutton extends input_field + { + var $type = 'radio'; + } + +class checkbox extends input_field + { + var $type = 'checkbox'; + + + function show($value='', $attrib=NULL) + { + // overwrite object attributes + if (is_array($attrib)) + $this->attrib = array_merge($this->attrib, $attrib); + + $this->attrib['type'] = $this->type; + + if ($value && (string)$value==(string)$this->attrib['value']) + $this->attrib['checked'] = TRUE; + else + $this->attrib['checked'] = FALSE; + + // return final tag + return sprintf('<%s%s />%s', + $this->_conv_case('input', 'tag'), + $this->create_attrib_string(), + ($this->newline ? "\n" : "")); + } + } + + +class textarea extends base_form_element + { + // PHP 5 constructor + function __construct($attrib=array()) + { + $this->attrib = $attrib; + + if ($attrib['newline']) + $this->newline = TRUE; + } + + // PHP 4 compatibility + function textarea($attrib=array()) + { + $this->__construct($attrib); + } + + function show($value='', $attrib=NULL) + { + // overwrite object attributes + if (is_array($attrib)) + $this->attrib = array_merge($this->attrib, $attrib); + + // take value attribute as content + if ($value=='') + $value = $this->attrib['value']; + + // make shure we don't print the value attribute + if (isset($this->attrib['value'])) + unset($this->attrib['value']); + + if (strlen($value)) + $value = rep_specialchars_output($value, 'html', 'replace', FALSE); + + // return final tag + return sprintf('<%s%s>%s</%s>%s', + $this->_conv_case('textarea', 'tag'), + $this->create_attrib_string(), + $value, + $this->_conv_case('textarea', 'tag'), + ($this->newline ? "\n" : "")); + } + } + + +class hiddenfield extends base_form_element + { + var $fields_arr = array(); + var $newline = TRUE; + + // PHP 5 constructor + function __construct($attrib=NULL) + { + if (is_array($attrib)) + $this->add($attrib); + } + + // PHP 4 compatibility + function hiddenfield($attrib=NULL) + { + $this->__construct($attrib); + } + + // add a hidden field to this instance + function add($attrib) + { + $this->fields_arr[] = $attrib; + } + + + function show() + { + $out = ''; + foreach ($this->fields_arr as $attrib) + { + $this->attrib = $attrib; + $this->attrib['type'] = 'hidden'; + + $out .= sprintf('<%s%s />%s', + $this->_conv_case('input', 'tag'), + $this->create_attrib_string(), + ($this->newline ? "\n" : "")); + } + + return $out; + } + } + + +class select extends base_form_element + { + var $options = array(); + + /* + syntax: + ------- + // create instance. arguments are used to set attributes of select-tag + $select = new select(array('name' => 'fieldname')); + + // add one option + $select->add('Switzerland', 'CH'); + + // add multiple options + $select->add(array('Switzerland', 'Germany'), + array('CH', 'DE')); + + // add 10 blank options with 50 chars + // used to fill with javascript (necessary for 4.x browsers) + $select->add_blank(10, 50); + + // generate pulldown with selection 'Switzerland' and return html-code + // as second argument the same attributes available to instanciate can be used + print $select->show('CH'); + */ + + // PHP 5 constructor + function __construct($attrib=NULL) + { + if (is_array($attrib)) + $this->attrib = $attrib; + + if ($attrib['newline']) + $this->newline = TRUE; + } + + // PHP 4 compatibility + function select($attrib=NULL) + { + $this->__construct($attrib); + } + + + function add($names, $values=NULL) + { + if (is_array($names)) + { + foreach ($names as $i => $text) + $this->options[] = array('text' => $text, 'value' => (string)$values[$i]); + } + else + { + $this->options[] = array('text' => $names, 'value' => (string)$values); + } + } + + + function add_blank($nr, $width=0) + { + $text = $width ? str_repeat(' ', $width) : ''; + + for ($i=0; $i < $nr; $i++) + $this->options[] = array('text' => $text); + } + + + function show($select=array(), $attrib=NULL) + { + $options_str = "\n"; + $value_str = $this->_conv_case(' value="%s"', 'attrib'); + + if (!is_array($select)) + $select = array((string)$select); + + foreach ($this->options as $option) + { + $selected = ((strlen($option['value']) && in_array($option['value'], $select, TRUE)) || + (in_array($option['text'], $select, TRUE))) ? $this->_conv_case(' selected', 'attrib') : ''; + + $options_str .= sprintf("<%s%s%s>%s</%s>\n", + $this->_conv_case('option', 'tag'), + strlen($option['value']) ? sprintf($value_str, $option['value']) : '', + $selected, + rep_specialchars_output($option['text'], 'html', 'replace', FALSE), + $this->_conv_case('option', 'tag')); + } + + // return final tag + return sprintf('<%s%s>%s</%s>%s', + $this->_conv_case('select', 'tag'), + $this->create_attrib_string(), + $options_str, + $this->_conv_case('select', 'tag'), + ($this->newline ? "\n" : "")); + } + } + + + + +// ********* rcube schared functions ********* + + +// provide details about the client's browser +function rcube_browser() + { + global $HTTP_USER_AGENT; + + $bw['ver'] = 0; + $bw['win'] = stristr($HTTP_USER_AGENT, 'win'); + $bw['mac'] = stristr($HTTP_USER_AGENT, 'mac'); + $bw['linux'] = stristr($HTTP_USER_AGENT, 'linux'); + $bw['unix'] = stristr($HTTP_USER_AGENT, 'unix'); + + $bw['ns4'] = stristr($HTTP_USER_AGENT, 'mozilla/4') && !stristr($HTTP_USER_AGENT, 'msie'); + $bw['ns'] = ($bw['ns4'] || stristr($HTTP_USER_AGENT, 'netscape')); + $bw['ie'] = stristr($HTTP_USER_AGENT, 'msie'); + $bw['mz'] = stristr($HTTP_USER_AGENT, 'mozilla/5'); + $bw['opera'] = stristr($HTTP_USER_AGENT, 'opera'); + $bw['safari'] = stristr($HTTP_USER_AGENT, 'safari'); + + if($bw['ns']) + { + $test = eregi("mozilla\/([0-9\.]+)", $HTTP_USER_AGENT, $regs); + $bw['ver'] = $test ? (float)$regs[1] : 0; + } + if($bw['mz']) + { + $test = ereg("rv:([0-9\.]+)", $HTTP_USER_AGENT, $regs); + $bw['ver'] = $test ? (float)$regs[1] : 0; + } + if($bw['ie']) + { + $test = eregi("msie ([0-9\.]+)", $HTTP_USER_AGENT, $regs); + $bw['ver'] = $test ? (float)$regs[1] : 0; + } + if($bw['opera']) + { + $test = eregi("opera ([0-9\.]+)", $HTTP_USER_AGENT, $regs); + $bw['ver'] = $test ? (float)$regs[1] : 0; + } + + if(eregi(" ([a-z]{2})-([a-z]{2})", $HTTP_USER_AGENT, $regs)) + $bw['lang'] = $regs[1]; + else + $bw['lang'] = 'en'; + + $bw['dom'] = ($bw['mz'] || $bw['safari'] || ($bw['ie'] && $bw['ver']>=5) || ($bw['opera'] && $bw['ver']>=7)); + $bw['pngalpha'] = $bw['mz'] || $bw['safari'] || ($bw['ie'] && $bw['ver']>=5.5) || + ($bw['ie'] && $bw['ver']>=5 && $bw['mac']) || ($bw['opera'] && $bw['ver']>=7) ? TRUE : FALSE; + + return $bw; + } + + +// get text in the desired language from the language file +function rcube_label($attrib) + { + global $sess_user_lang, $INSTALL_PATH; + static $sa_text_data, $s_language; + + // extract attributes + if (is_string($attrib)) + $attrib = array('name' => $attrib); + + $nr = is_numeric($attrib['nr']) ? $attrib['nr'] : 1; + $vars = isset($attrib['vars']) ? $attrib['vars'] : ''; + + $command_name = strlen($attrib['command']) ? $attrib['command'] : NULL; + $alias = $attrib['name'] ? $attrib['name'] : ($command_name && $command_label_map[$command_name] ? $command_label_map[$command_name] : ''); + + + // load localized texts + if (!$sa_text_data || $s_language != $sess_user_lang) + { + $sa_text_data = array(); + + // get english labels (these should be complete) + @include($INSTALL_PATH.'program/localization/en/labels.inc'); + @include($INSTALL_PATH.'program/localization/en/messages.inc'); + + if (is_array($labels)) + $sa_text_data = $labels; + if (is_array($messages)) + $sa_text_data = array_merge($sa_text_data, $messages); + + // include user language files + if ($sess_user_lang!='en' && is_dir($INSTALL_PATH.'program/localization/'.$sess_user_lang)) + { + include_once($INSTALL_PATH.'program/localization/'.$sess_user_lang.'/labels.inc'); + include_once($INSTALL_PATH.'program/localization/'.$sess_user_lang.'/messages.inc'); + + if (is_array($labels)) + $sa_text_data = array_merge($sa_text_data, $labels); + if (is_array($messages)) + $sa_text_data = array_merge($sa_text_data, $messages); + } + + $s_language = $sess_user_lang; + } + + // text does not exist + if (!($text_item = $sa_text_data[$alias])) + { + /* + raise_error(array('code' => 500, + 'type' => 'php', + 'line' => __LINE__, + 'file' => __FILE__, + 'message' => "Missing localized text for '$alias' in '$sess_user_lang'"), TRUE, FALSE); + */ + return "[$alias]"; + } + + // make text item array + $a_text_item = is_array($text_item) ? $text_item : array('single' => $text_item); + + // decide which text to use + if ($nr==1) + $text = $a_text_item['single']; + else if ($nr>0) + $text = $a_text_item['multiple']; + else if ($nr==0) + { + if ($a_text_item['none']) + $text = $a_text_item['none']; + else if ($a_text_item['single']) + $text = $a_text_item['single']; + else if ($a_text_item['multiple']) + $text = $a_text_item['multiple']; + } + + // default text is single + if ($text=='') + $text = $a_text_item['single']; + + + // replace vars in text + if (is_array($attrib['vars'])) + { + foreach ($attrib['vars'] as $var_key=>$var_value) + $a_replace_vars[substr($var_key, 0, 1)=='$' ? substr($var_key, 1) : $var_key] = $var_value; + } + + if ($a_replace_vars) + $text = preg_replace('/\${?([_a-z]{1}[_a-z0-9]*)}?/ei', '$a_replace_vars["\1"]', $text); + + // remove variables in text which were not available in arg $vars and $nr + eval("\$text = <<<EOF +$text +EOF; +"); + + + // format output + if (($attrib['uppercase'] && strtolower($attrib['uppercase']=='first')) || $attrib['ucfirst']) + return ucfirst($text); + else if ($attrib['uppercase']) + return strtoupper($text); + else if ($attrib['lowercase']) + return strtolower($text); + else + return $text; + + return $text; + } + + +// send HTTP header for no-cacheing steps +function send_nocacheing_headers() + { + if (headers_sent()) + return; + + header("Expires: ".gmdate("D, d M Y H:i:s")." GMT"); + header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); + header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); + header("Pragma: no-cache"); + } + + +// send header with expire date 30 days in future +function send_future_expire_header() + { + if (!headers_sent()) + header("Expires: ".gmdate("D, d M Y H:i:s", mktime()+2600000)." GMT"); + } + + +// replace specials characters to a specific encoding type +function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE) + { + global $OUTPUT_TYPE; + static $html_encode_arr, $js_rep_table, $rtf_rep_table, $xml_rep_table; + + if (!$enctype) + $enctype = $GLOBALS['OUTPUT_TYPE']; + + // convert nbsps back to normal spaces if not html + if ($enctype!='html') + $str = str_replace(chr(160), ' ', $str); + + + // encode for plaintext + if ($enctype=='text') + return str_replace("\r\n", "\n", $mode=='remove' ? strip_tags($str) : $str); + + // encode for HTML output + if ($enctype=='html') + { + if (!$html_encode_arr) + { + $html_encode_arr = get_html_translation_table(HTML_ENTITIES); + $html_encode_arr["?"] = '–'; + $html_encode_arr[chr(128)] = '€'; + unset($html_encode_arr['?']); + unset($html_encode_arr['&']); + } + + $ltpos = strpos($str, '<'); + $encode_arr = $html_encode_arr; + + // don't replace quotes and html tags + if (($mode=='show' || $mode=='') && $ltpos!==false && strpos($str, '>', $ltpos)!==false) + { + unset($encode_arr['"']); + unset($encode_arr['<']); + unset($encode_arr['>']); + } + else if ($mode=='remove') + $str = strip_tags($str); + + $out = strtr($str, $encode_arr); + + return $newlines ? nl2br($out) : $out; + } + + + if ($enctype=='url') + return rawurlencode($str); + + + // if the replace tables for RTF, XML and JS are not yet defined + if (!$js_rep_table) + { + for ($c=160; $c<256; $c++) // can be increased to support more charsets + { + $hex = dechex($c); + $js_rep_table[Chr($c)] = sprintf("\u%s%s", str_repeat('0', 4-strlen($hex)), $hex); + $rtf_rep_table[Chr($c)] = "\\'$hex"; + $xml_rep_table[Chr($c)] = "&#$c;"; + } + + $js_rep_table['"'] = sprintf("\u%s%s", str_repeat('0', 4-strlen(dechex(34))), dechex(34)); + $xml_rep_table['"'] = '"'; + } + + // encode for RTF + if ($enctype=='xml') + return strtr($str, $xml_rep_table); + + // encode for javascript use + if ($enctype=='js') + return preg_replace(array("/\r\n/", '/"/', "/'/"), array('\n', '\"', "\'"), strtr($str, $js_rep_table)); + + // encode for RTF + if ($enctype=='rtf') + return preg_replace("/\r\n/", "\par ", strtr($str, $rtf_rep_table)); + + // no encoding given -> return original string + return $str; + } + + +function decode_specialchars($input, $charset='') + { + $charset = strtolower($charset); + + if (strcasecmp($charset, 'utf-8')==0) + return utf8_decode($input); + else if ($charset=="koi8-r") + return convert_cyr_string($input, 'k', 'w'); + else if ($charset=="iso8859-5") + return convert_cyr_string($input, 'i', 'w'); + else if ($charset=="x-cp866") + return convert_cyr_string($input, 'a', 'w'); + else if ($charset=="x-mac-cyrillic") + return convert_cyr_string($input, 'm', 'w'); + + return $input; + } + + + +// function to convert an array to a javascript array +function array2js($arr, $type='') + { + if (!$type) + $type = 'mixed'; + + if (is_array($arr)) + { + // no items in array + if (!sizeof($arr)) + return 'new Array()'; + else + { + $a_pairs = array(); + $keys_arr = array_keys($arr); + $is_assoc = $have_numeric = 0; + + for ($i=0; $i<sizeof($keys_arr); ++$i) + { + if(is_numeric($keys_arr[$i])) + $have_numeric = 1; + if (!is_numeric($keys_arr[$i]) || $keys_arr[$i]!=$i) + $is_assoc = 1; + if($is_assoc && $have_numeric) + break; + } + + $previous_was_array = false; + while (list($key, $value) = each($arr)) + { + // enclose key with quotes if it is not variable-name conform + if (!ereg("^[_a-zA-Z]{1}[_a-zA-Z0-9]*$", $key) /* || is_js_reserved_word($key) */) + $key = "'$key'"; + + if (!is_array($value)) + { + $value = str_replace("\r\n", '\n', $value); + $value = str_replace("\n", '\n', $value); + } + + $is_string = false; + if (!is_array($value)) + { + if ($type=='string') + $is_string = true; + else if ((($type=='mixed' && is_numeric($value)) || $type=='int') && strlen($value)<16) // js interprets numbers with digits >15 as ...e+... + $is_string = FALSE; + else + $is_string = TRUE; + } + + if ($is_string) + $value = "'".preg_replace("/(?<!\\\)'/", "\'", $value)."'"; + + $a_pairs[] = sprintf("%s%s", + $is_assoc ? "$key:" : '', + is_array($value) ? array2js($value, $type) : $value); + } + + if ($a_pairs) + { + if ($is_assoc) + $return = '{'.implode(',', $a_pairs).'}'; + else + $return = '['.implode(',', $a_pairs).']'; + } + + return $return; + } + } + else + return $arr; + } + + +// similar function as in_array() ut case-insensitive +function in_array_nocase($needle, $haystack) + { + foreach ($haystack as $value) + { + if (strtolower($needle)===strtolower($value)) + return TRUE; + } + + return FALSE; + } + + + +// find out if the string content means TRUE or FALSE +function get_boolean($str) + { + $str = strtolower($str); + if(in_array($str, array('false', '0', 'no', 'nein', ''), TRUE)) + return FALSE; + else + return TRUE; + } + + +function show_bytes($numbytes) + { + if ($numbytes > 1024) + return sprintf('%d KB', round($numbytes/1024)); + else + return sprintf('%d B', $numbytes); + } + + +// convert paths like ../xxx to an absolute path using a base url +function make_absolute_url($path, $base_url) + { + $host_url = $base_url; + $abs_path = $path; + + // cut base_url to the last directory + if (strpos($base_url, '/')>7) + { + $host_url = substr($base_url, 0, strpos($base_url, '/')); + $base_url = substr($base_url, 0, strrpos($base_url, '/')); + } + + // $path is absolute + if ($path{0}=='/') + $abs_path = $host_url.$path; + else + { + // strip './' because its the same as '' + $path = preg_replace('/^\.\//', '', $path); + + if(preg_match_all('/\.\.\//', $path, $matches, PREG_SET_ORDER)) + foreach($matches as $a_match) + { + if (strrpos($base_url, '/')) + $base_url = substr($base_url, 0, strrpos($base_url, '/')); + + $path = substr($path, 3); + } + + $abs_path = $base_url.'/'.$path; + } + + return $abs_path; + } + + + +?>
\ No newline at end of file diff --git a/program/include/session.inc b/program/include/session.inc new file mode 100644 index 000000000..c68b3dba9 --- /dev/null +++ b/program/include/session.inc @@ -0,0 +1,154 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | program/include/session.inc | + | | + | This file is part of the RoundCube Webmail client | + | Copyright (C) 2005, RoundCube Dev, - Switzerland | + | All rights reserved. | + | | + | PURPOSE: | + | Provide database supported session management | + | | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + + +function sess_open($save_path, $session_name) + { + return TRUE; + } + + + +function sess_close() + { + return TRUE; + } + + +// read session data +function sess_read($key) + { + global $DB, $SESS_CHANGED; + + $sql_result = $DB->query(sprintf("SELECT vars, UNIX_TIMESTAMP(changed) AS changed + FROM %s + WHERE sess_id='%s'", + get_table_name('session'), + $key)); + + if ($sql_arr = $DB->fetch_assoc($sql_result)) + { + $SESS_CHANGED = $sql_arr['changed']; + + if (strlen($sql_arr['vars'])) + return $sql_arr['vars']; + } + + return FALSE; + } + + +// save session data +function sess_write($key, $vars) + { + global $DB; + + $sql_result = $DB->query(sprintf("SELECT 1 + FROM %s + WHERE sess_id='%s'", + get_table_name('session'), + $key)); + + if ($DB->num_rows($sql_result)) + { + session_decode($vars); + $DB->query(sprintf("UPDATE %s + SET vars='%s', + changed=NOW() + WHERE sess_id='%s'", + get_table_name('session'), + $vars, + $key)); + } + else + { + $DB->query(sprintf("INSERT INTO %s + (sess_id, vars, created, changed) + VALUES ('%s', '%s', NOW(), NOW())", + get_table_name('session'), + $key, + $vars)); + } + + return TRUE; + } + + +// handler for session_destroy() +function sess_destroy($key) + { + global $DB; + + $DB->query(sprintf("DELETE FROM %s + WHERE sess_id='%s'", + get_table_name('session'), + $key)); + + // also delete session entries in cache table + $DB->query(sprintf("DELETE FROM %s + WHERE session_id='%s'", + get_table_name('cache'), + $key)); + + return TRUE; + } + + +// garbage collecting function +function sess_gc($maxlifetime) + { + global $DB; + + // get all expired sessions + $sql_result = $DB->query(sprintf("SELECT sess_id + FROM %s + WHERE UNIX_TIMESTAMP(NOW())-UNIX_TIMESTAMP(created) > %d", + get_table_name('session'), + $maxlifetime)); + + $a_exp_sessions = array(); + while ($sql_arr = $DB->fetch_assoc($sql_result)) + $a_exp_sessions[] = $sql_arr['sess_id']; + + + if (sizeof($a_exp_sessions)) + { + // delete session records + $DB->query(sprintf("DELETE FROM %s + WHERE sess_id IN ('%s')", + get_table_name('session'), + join("','", $a_exp_sessions))); + + // also delete session cache records + $DB->query(sprintf("DELETE FROM %s + WHERE session_id IN ('%s')", + get_table_name('cache'), + join("','", $a_exp_sessions))); + } + + return TRUE; + } + + +// set custom functions for PHP session management +session_set_save_handler('sess_open', 'sess_close', 'sess_read', 'sess_write', 'sess_destroy', 'sess_gc'); + +?> |