<?php
/**
* Proivdes item storage functions for use within the filing system
* @package phlyMail Nahariya 4.0+
* @subpackage Files handler
* @subpackage FS Storage Driver
* @copyright 2003-2010 phlyLabs, Berlin (http://phlylabs.de)
* @version 4.0.8 2010-06-10
*/
// Only valid within phlyMail
if (!defined('_IN_PHM_')) die();
class files_storage {
// Default setting for pagesize: false (unlimited);
public $pagesize = false;
private $error = array();
public $docroot = false;
public $userroot = false;
public $sysfolders = array
('root' => array('root' => 1, 'msg' => 'MyFilesRootFolder', 'de' => 'Dateien', 'en' => 'Files', 'icon' => ':files')
,'waste' => array('root' => 0, 'msg' => 'EmailWasteFolder', 'de' => 'Papierkorb', 'en' => 'Trash', 'icon' => ':waste')
);
/**
* Constructor, expects to be given 2 parameters
* @param string Path to INI file
* @param int ID of the affected user
*[@param string Actual working dir within doc root]
*[@param boolean TRUE to create the user's doc root, FALSE otherwise; Default: FALSE]
* @return boolean false if either dir does not exist or UID not given, true otherwise
*/
public function __construct($uid = '', $dirname = '', $create = false)
{
if (false === $uid) return false;
// Load indexer driver, instantiate it
require_once(dirname(__FILE__).'/indexer.mysql.php');
$this->IDX = new files_indexer();
$this->uid = intval($uid);
$this->place = false;
$this->docroot = $GLOBALS['_PM_']['path']['storage'];
$this->userroot = $this->docroot.'/'.$this->uid.'/files';
if ($this->uid > 0 && $create && !basics::create_dirtree($this->userroot)) return false;
if (file_exists($this->docroot)) {
if ($dirname) $this->place = $dirname;
return true;
}
return false;
}
public function set_parameter($option, $value = false)
{
if (!is_array($option)) {
$option = array($option => $value);
}
foreach ($option as $k => $v) {
switch ($k) {
case 'pagesize':
$this->pagesize = ($v > 0) ? $v : false;
break;
default:
$this->set_error('Set Parameter: Unknown option '.$k);
return false;
}
}
return true;
}
private function set_error($error)
{
if (isset($this->append_errors) && $this->append_errors) {
$this->error[] = $error;
} else {
$this->error[0] = $error;
}
}
public function get_errors($nl = "\n")
{
$error = implode($nl, $this->error);
if (!isset($this->retain_erros) || !$this->retain_erros) {
$this->error = array();
}
return $error;
}
/**
* Removes all saved information of a certain user from the
* index and optionally the file system
*[@param boolean TRUE for also deleting all data from the file system; Default: TRUE]
* @return boolean State of the operation
* @since 0.2.4
*/
public function remove_user($fstoo = true)
{
$state = $this->IDX->remove_user($this->uid);
if (!$state) return false;
if (!$fstoo) return true;
// Deleting the dir depends on the OS we are running on
basics::removedir($this->userroot);
}
/**
* Called on installing the handler from the Config interface
* @param void
* @return boolean
* @since 0.0.7
*/
public function handler_install()
{
return $this->IDX->handler_install();
}
/**
* Called on uninstalling the handler from the Config interface
* @param void
* @return boolean
* @since 0.0.7
*/
public function handler_uninstall()
{
return $this->IDX->handler_uninstall();
}
public function init_folders()
{
$this->fidx = $this->IDX->get_folder_structure($this->uid);
return true;
}
/**
* Read all available folders below doc root and return as multidim array,
* this method is probably only useful for the initial display of all folders
* within the frontend's folder screen
* @param void
* @return multi dim array folder structure and meta data
*/
public function read_folders($parent_id = 0, $path = '')
{
$return = false;
// Not valid parent ID
if (!isset($this->fidx[$parent_id])) return false;
foreach ($this->fidx[$parent_id] as $k => $v) {
$return[$k]['path'] = $k;
$return[$k]['path_canon'] = (isset($this->fidx[$parent_id]['path_canon']) ? $this->fidx[$parent_id]['path_canon'] : '')
.'/'.($v['icon'] == ':files' ? '' : $v['friendly_name']);
$return[$k]['icon'] = $v['icon'];
$return[$k]['foldername'] = $v['friendly_name'];
$return[$k]['type'] = $v['type'];
$return[$k]['has_folders'] = $v['has_folders'];
$return[$k]['has_items'] = ($v['icon'] == ':files' || $v['icon'] == ':waste') ? 1 : $v['has_items'];
if (isset($this->fidx[$k])) {
$return[$k]['subdirs'] = $this->read_folders($k);
} else {
$return[$k]['subdirs'] = false;
}
}
return $this->translate($return, $GLOBALS['WP_msg']);
}
/**
* Read all available folders below doc root and return as array,
* opposed to read_folders() the returned array does not reflect the real
* structure of the folders, just the order and a 'level' attribute will tell
* you about it.
* @param void
* @return array of folders and their meta data
*/
public function read_folders_flat($parent_id = 0, $level = 0)
{
$return = false;
// Not valid parent ID
if (!isset($this->fidx[$parent_id])) return false;
foreach ($this->fidx[$parent_id] as $k => $v) {
$return[$k]['path'] = $k;
$return[$k]['path_canon'] = (isset($this->fidx[$parent_id]['path_canon']) ? $this->fidx[$parent_id]['path_canon'] : '')
.'/'.($v['icon'] == ':files' ? '' : $v['friendly_name']);
$return[$k]['icon'] = $v['icon'];
$return[$k]['foldername'] = $v['friendly_name'];
$return[$k]['type'] = $v['type'];
$return[$k]['has_folders'] = $v['has_folders'];
$return[$k]['has_items'] = ($v['icon'] == ':files' || $v['icon'] == ':waste') ? 1 : $v['has_items'];
$return[$k]['level'] = $level;
$return[$k]['childof'] = $v['childof'];
if (isset($this->fidx[$k])) {
$return[$k]['subdirs'] = true;
$return = $return + $this->read_folders_flat($k, $level+1);
} else {
$return[$k]['subdirs'] = false;
}
}
return $this->translate($return, $GLOBALS['WP_msg']);
}
/**
* Check for the existance of a certain foldername; by specifying the parent
* folder this method will check for the existance within the given parent
* only, thus allowing to prevent duplicate folder names
*
* @param string $folder Display name of the folder to search for
* [@param int $childof ID of the folder to limit the search to]
* @return bool TRUE, if found, FALSE otherwise
* @since v0.0.6
* @see indexer::folder_exists()
*/
public function folder_exists($folder, $childof = false)
{
if (!$folder) return false;
return $this->IDX->folder_exists($this->uid, $folder, $childof);
}
/**
* Create a new folder within a given one
*
* @param string $folder Display name of the folder to create
* @param int $childof ID of the parent folder
*[@param int $type The type of the folder; default is 1 (user created folder)]
*[@param string $icon Path to an icon to assign this folder]
*[@param bool $has_folders Whether this folder can contain subfolders]
*[@param bool $has_items Whether this folder can contain any items]
*[@param string $path Optional fs path for the new folder, only interesting for system folders]
* @return int New folder's ID in index if successful; FALSE otherwise
* @since v0.0.6
* @see indexer::create_folder()
* @see indexer::update_folder()
*/
public function create_folder($folder, $childof, $type = 1, $icon = '', $has_folders = true, $has_items = true, $path = '')
{
if (!$folder || false === $childof || is_null($childof)) return false;
// Check, whether we are allowed to create the new folder there
if (!is_writable($this->userroot)) {
$this->set_error('Insufficient permissions to create folder');
return false;
}
// Create folder's index and retrieve its ID
$new_folder = $this->IDX->create_folder(array
('uid' => $this->uid
,'friendly_name' => $folder
,'folder_path' => ($path != '') ? $path : ''
,'childof' => $childof
,'type' => $type
,'icon' => $icon
,'has_folders' => $has_folders
,'has_items' => $has_items
));
ob_start();
// This is a named folder
if ($path != '') {
$new_folder = $path;
}
// Try to create the physical folder
$state = basics::create_dirtree($this->userroot.'/'.$new_folder);
if (!$state) {
$this->set_error('Error in mkdir "'.$this->userroot.'/'.$new_folder.'": '.ob_get_clean());
// Remove index information again
$this->IDX->remove_folder($this->uid, $new_folder, false);
return false;
}
ob_end_clean();
// In case of a named folder path, we are done here
if ($path != '') return $new_folder;
// Update folder path in index accordingly (if no path name was given)
$this->IDX->update_folder(array
('uid' => $this->uid
,'id' => $new_folder
,'folder_path' => $new_folder
));
return $new_folder;
}
/**
* Creates an internal folder, which will not appear in the index
* @param string $path Path of the folder within the docroot
* @return boolean TRUE on success; FALSE otherwise
* @since 0.2.3
*/
public function create_internal_folder($path)
{
if (!$path) {
$this->set_error('Please give me a path to create');
return false;
}
if (file_exists($this->userroot.'/'.$path) && is_dir($this->userroot.'/'.$path)) return true;
ob_start();
// Try to create the physical folder
$state = basics::create_dirtree($this->userroot.'/'.$path);
if (!$state) {
$this->set_error('Error in mkdir "'.$this->userroot.'/'.$path.'": '.ob_get_clean());
return false;
}
ob_end_clean();
return true;
}
/**
* Creates a itembox root folder in the indexer. The itembox folder is NOT created in the file system
*
* @param string $folder Display name of the folder to create
*[@param int $type The type of the itembox; default is 0 (system folder)]
*[@param string $icon Path to an icon to assign this folder]
*[@param bool $has_folders Whether this folder can contain subfolders]
*[@param bool $has_items Whether this folder can contain any items]
* @return int New itembox' ID in index if successful; FALSE otherwise
* @since v0.2.3
* @see indexer::create_folder()
*/
public function create_mailbox($folder, $type = 0, $icon = '', $has_folders = true, $has_items = false)
{
if (!$folder) return false;
// Create folder's index and retrieve its ID
$new_folder = $this->IDX->create_folder(array
('uid' => $this->uid
,'friendly_name' => $folder
,'folder_path' => ''
,'childof' => 0
,'type' => $type
,'icon' => $icon
,'has_folders' => $has_folders
,'has_items' => $has_items
));
$this->error = $this->IDX->get_errors();
return $new_folder;
}
/**
* Rename a folder (change its friendly name)
*
* @param int $id The ID of the folder to give a new name to
* @param string $name New name of the folder
* @return bool
* @see indexer::update_folder()
*/
public function rename_folder($id, $name)
{
// Clean implementatins should not fail here
if (!$id || !$name) return false;
return $this->IDX->update_folder(array
('uid' => $this->uid
,'id' => $id
,'friendly_name' => $name
));
}
/**
* Remove a folder again (from Indexer and FileSystem)
* This is done recursively, so watch out for larger structures, which could
* need too long for PHPs max_execution_time!
*
* @param int $id The unique ID of the folder to remove
* @param bool TRUE, if the folder should not be moved to the waste bin
* @param bool TRUE to allow deleting system folders, FALSE not to; Default: true
* @return bool TRUE on success, FALSE on failure
* @see indexer::remove_folder()
*/
public function remove_folder($id, $forced = false, $system = true)
{
// Folders are only really deleted, when the correct flag is given or they are
// a *direct* child of the waste bin
$info = $this->get_folder_info($id);
// System folders should not be deleted through the frontend
if (!$system && $info['type']%10 == 0) return false;
if (!$forced) {
$move = false;
$waste = $this->get_folder_id_from_path('waste', true);
if (0 == $waste) {
$move = false;
} else {
$move = !($this->folder_is_in_waste($info));
}
if ($move) return $this->move_folder($id, $waste);
}
// Retrieve affected subfolders
$list = $this->read_folders_flat($id, 1);
// Add current folder to the list and adapt the information
$list[0] = $info;
$list[0]['level'] = 0;
$list[0]['path'] = $list[0]['folder_path'];
// Apply sorting by level in descending order - this causes
// the folders to be deleted from deepest to highest, thus making sure,
// that even if the script runs for too long, no orphans without parent
// are left over
if (count($list) > 1) {
$sort = array();
foreach ($list as $k => $v) { $sort[$k] = $v['level']; }
array_multisort($sort, SORT_DESC, $list);
}
// Go ahead, deleting everything in sight
foreach ($list as $k => $v) {
// Try to remove index entry
$success = $this->IDX->remove_folder($this->uid, $this->get_folder_id_from_path($v['path']), false, true);
if (!$success) {
$this->set_error('Could not remove folder: '.$this->IDX->get_errors());
return false;
}
basics::removedir($this->userroot.'/'.$v['path']);
}
return true;
}
/**
* This is just a helper method for remove_folder()
* It tries to find out, whether the folder to delete is a child of a waste folder
*
* @param array $info Folder Info array of the folder
* @return bool TRUE for this is a child of a waste folder, FALSE if not
* @since 0.5.1
*/
private function folder_is_in_waste($info)
{
while ($info['childof'] != 0) {
$info = $this->get_folder_info($info['childof']);
if ($info['icon'] == ':waste') return true;
}
return false;
}
/**
* Resyncs index fields with real amount of messages, unread and unseen states
*
* @param int $id Unique ID of the folder to resync
* @return bool TRUE on succes, FALSE on failure
* @since 0.4.2
*/
public function resync_folder($id) { return $this->IDX->resync_folder($this->uid, $id); }
/**
* Moving a folder within the folder hierarchy
* By moving we mean changing the parent folder info only, since all folders
* of a certain itembox are stored wihtin the same physical folder
*
* @param int $id The unqiue ID of the folder to move
* @param int $childof The new parent folder ID
* @return bool TRUE on success, FALSE on failure
*/
public function move_folder($id, $childof)
{
// Update folder path in index accordingly
return $this->IDX->update_folder(array
('uid' => $this->uid
,'id' => $id
,'childof' => $childof
));
}
public function get_folder_info($folder)
{
return $this->IDX->get_folder_info($this->uid, $folder);
}
/**
* Returns the ID of the folder, matching path
*
* @param string Path of the folder
* @return int ID of the folder on success, false in failure
* @since 0.1.8
*/
public function get_folder_id_from_path($path)
{
return $this->IDX->get_folder_id_from_path($this->uid, $path);
}
/**
* Read in item index for specific folder, if folder not already specified
* on construct, it must be given here
*[@param string Dir to read, not necessary if given on construct]
*[@param int $offset Where to start getting item list]
*[@param int $pagesize How many items are on one page]
*[@param string $ordby DB field to order the list by]
*[@param ASC|DESC $orddir order direction]
* @return mixed false, if dir not given; empty array, if no content;
* array('items' => number of items, 'size' => raw size of items
*/
public function init_items($folder = false, $offset = false, $pagesize = 0, $ordby = false, $orddir = 'ASC')
{
// If no dir to work on specified, give up
if (!$this->place && !$folder) return false;
if (!isset($this->place) || !$this->place) $this->place = $folder;
$folderdata = $this->IDX->get_folder_info($this->uid, $this->place);
if (isset($folderdata['itemnum']) && $folderdata['itemnum']) {
$this->midx = $this->IDX->get_item_list($this->uid, $this->place, $offset, $pagesize, $ordby, $orddir);
return array('items' => $folderdata['itemnum'], 'size' => $folderdata['itemsize']);
} else {
$this->midx = array();
return array('items' => 0, 'size' => 0);
}
}
/**
* Returns header fields of a given item ID. This is fetched from the index data created by
* $this->init_items()
* @param int ID of item to fetch data of
* [@param bool Set to true, if info should be fetched from the indexer directly]
* @return mixed false on error; empty array if impossible to retrieve data;
* array with header fields on success
*/
public function get_item_info($id, $direct = false)
{
if ($direct) {
$return = $this->IDX->get_item_list($this->uid, 0, null, null, null, null, $id);
return $return[0];
}
if (!isset($this->midx)) {
if (!$this->init_items()) return false;
}
$return = isset($this->midx[$id]) ? $this->midx[$id] : array();
return $return;
}
/**
* Get the complete path to a given item
*
* @param int ID of the item
* @return array|string path to the item, false on failure
* @since 0.1.8
*/
public function item_get_real_location($item, $as_string = false)
{
$return = $this->IDX->item_get_real_location($this->uid, $item);
if (!is_array($return) || !isset($return[1]) || !$return[1]) {
return array(false, false);
}
$path = str_replace('//', '/', $this->userroot.'/'.$return[0].'/'.$return[1]);
return (!file_exists($path)) ? ($as_string ? false : array(false, false)) : ($as_string ? $path : $return);
}
public function item_exists($name, $folder)
{
return $this->IDX->item_exists($this->uid, $name, $folder);
}
/**
* Open a stream to given item for file system operations
* @param int ID of the item
* @param string Mode flag, see PHP function fopen() for possible values
* @return resource Resource ID of the opened stream, false on failure
*/
public function item_open_stream($item = 0, $flag = 'r')
{
list ($folderpath, $filename) = $this->IDX->item_get_real_location($this->uid, $item);
$path = $this->userroot.'/'.$folderpath.'/'.$filename;
if (!file_exists($path)) return false;
$this->fh = fopen($path, $flag);
return (!is_resource($this->fh) || !$this->fh) ? false : $this;
}
/**
* Set the file pointer of the current stream to a certain position to continue reading
* from there
* @param int Offset in bytes to point to afterwards
* @return bool TRUE on success, FALSE otherwise
* @since 0.1.6
*/
public function item_seek_stream($offset = 0)
{
if (!isset($this->fh) || !is_resource($this->fh)) return false;
$ret = fseek($this->fh, $offset);
return ($ret);
}
/**
* Reads data from a item file from the current position up to the number of bytes specified
* Use item_seek_stream() to set the file pointer to your desired start position
* @param int Number of bytes to read, if set to 0, one line from the stream is returned
* @return mixed String data read from item stream on success, FALSE on EOF or failure
* @since 0.1.6
*/
public function item_read_stream($length = 0)
{
if (!isset($this->fh) || !is_resource($this->fh)) return false;
@set_magic_quotes_runtime(0);
if (!$length) {
if (false !== feof($this->fh)) {
fclose($this->fh);
unset($this->fh);
return false;
}
$line = fgets($this->fh, 1024);
return $line;
}
return fread($this->fh, $length);
}
/**
* Closes a previously opened stream again
* @param void
* @return void
* @since 0.2.2
*/
public function item_close_stream()
{
if (isset($this->fh) && is_resource($this->fh)) {
fclose($this->fh);
unset($this->fh);
}
}
/**
* Move a item in the file system and the indexer as well
* @param int ID of the item to move
* @param int folder ID to move the item to
* @return bool TRUE on success, false otherwise
* @since 0.0.9
*/
public function move_item($id, $folder, $forced = false)
{
// Make sure we don't try to copy a item onto itself and delete it afterwards
$info = $this->get_item_info($id, true);
if ($info['folder_id'] == $folder) return true;
list ($path, $filename) = $this->IDX->item_get_real_location($this->uid, $id);
if ($path) $path .= '/';
$info = $this->IDX->get_folder_info($this->uid, $folder);
if (!$info || empty($info)) {
$this->set_error('I don\'t know the folder '.$folder);
return false;
}
$from_path = $this->userroot.'/'.$path.$filename;
$to_path = $this->userroot.'/'.$info['folder_path'];
if (!file_exists($from_path)) {
$this->set_error($from_path.' does not exist');
return false;
}
if (!file_exists($to_path) || !is_dir($to_path)) basics::create_dirtree($to_path);
if (!is_readable($from_path) || !is_writable($to_path)) {
$this->set_error('Read from '.$from_path.' or write to '.$to_path.' not possible');
return false;
}
$res = copy($from_path, $to_path.'/'.$filename);
if (!$res) {
$this->set_error('Copying in the file system failed ('.$from_path.' -> '.$to_path.'/'.$filename.')');
return false;
}
$this->IDX->item_move($this->uid, $id, $folder, $forced);
$old_umask = umask(0);
chmod($to_path.'/'.$filename, $GLOBALS['_PM_']['core']['file_umask']);
umask($old_umask);
return unlink($from_path);
}
/**
* Copy a item in the file system and the indexer as well
* @param int ID of the item to move
* @param int folder ID to move the item to
* @return bool TRUE on success, false otherwise
* @since 0.1.4
*/
public function copy_item($id, $folder, $forced = false)
{
list ($path, $filename) = $this->IDX->item_get_real_location($this->uid, $id);
if ($path) $path .= '/';
$info = $this->IDX->get_folder_info($this->uid, $folder);
if (!$info || empty($info)) {
$this->set_error('I don\'t know the folder '.$folder);
return false;
}
$from_path = $this->userroot.'/'.$path.$filename;
$to_path = $this->userroot.'/'.$info['folder_path'];
if (!file_exists($from_path)) {
$this->set_error($from_path.' does not exist');
return false;
}
if (!file_exists($to_path) || !is_dir($to_path)) basics::create_dirtree($to_path);
if (!is_readable($from_path) || !is_writable($to_path)) {
$this->set_error('Read from '.$from_path.' or write to '.$to_path.' not possible');
return false;
}
// Give the item a new ID
$filename = uniqid(time().'.', true);
$res = copy($from_path, $to_path.'/'.$filename);
if (!$res) {
$this->set_error('Copying in the file system failed ('.$from_path.' -> '.$to_path.'/'.$filename.')');
return false;
}
$old_umask = umask(0);
chmod($to_path.'/'.$filename, $GLOBALS['_PM_']['core']['file_umask']);
umask($old_umask);
return $this->IDX->item_copy($this->uid, $id, $folder, $filename, $forced);
}
/**
* Delete a item from the file system and the indexer as well
*
* [@param int ID of the item to remove]
* [@param int folder ID to empty, only supported with WASTE in the moment]
* @return bool TRUE on success, false otherwise
* @since 0.1.1
*/
public function delete_item($id = false, $folder = false, $forced = false)
{
if (false !== $folder) {
$info = $this->IDX->get_folder_info($this->uid, $folder);
if ('waste' == $info['folder_path']) {
$this->IDX->item_delete($this->uid, false, $folder);
$d = opendir($this->userroot.'/'.$info['folder_path']);
while (false != ($file = readdir($d))) {
if ('.' == $file) continue;
if ('..' == $file) continue;
@unlink($this->userroot.'/'.$info['folder_path'].'/'.$file);
}
closedir($d);
return true;
}
} else {
list ($path, $filename) = $this->IDX->item_get_real_location($this->uid, $id);
if (!$filename) return true;
$from_path = $this->userroot.'/'.($path ? $path.'/' : '').$filename;
// File might be missing -> just remove it from the index
if (!file_exists($from_path) || !is_readable($from_path) || !is_writable($from_path)) {
return $this->IDX->item_delete($this->uid, $id, false);
}
// Mails are not deleted directly, instead they get moved to the trash
if ($path != 'waste' && !$forced) {
return $this->move_item($id, $this->get_folder_id_from_path('waste'));
}
$ret = $this->IDX->item_delete($this->uid, $id, false);
if (!$ret) $this->set_error($this->IDX->get_errors());
unlink($from_path);
return $ret;
}
}
/**
* Rename an item (change its friendly name)
*
* @param int $id The ID of the item to give a new name to
* @param string $name New name of the item
*[@param string $mime New MIME type of the item
* @return bool
* @see indexer::update_item()
*/
public function rename_item($id, $name, $mime = null)
{
// Clean implementatins should not fail here
if (!$id || !$name) return -3;
return $this->IDX->item_rename($this->uid, $id, $name, $mime);
}
/**
* Add a item to the storage and indexer
* @param array item data
* [- folder_path string Path of the folder within docroot to save the item to]
* [- folder_id int ID of the folder, either this or the folder_path MUST be given;
* if both are given, the ID takes precedence]
* - filename string Filename of the item
* - friendlyname string Human readable name of the item
* - type string MIME type of the item
* - size int Size in bytes fo the whole file
* - img_w int Width of the item, if an image (JPEG, PNG, ...)
* - img_h int Height of the item, if an image (JPEG, PNG, ...)
* - filed boolean TRUE, if the item is already saved in the specified location, FALSE if not;
* if FALSE is specified, one should pass an open file handle as the second parameter,
* where the item will be read from
*[@param resource Open stream to read the item data from]
* @return int $ID ID of the newly created DB item
* @since 0.1.0
*/
public function file_item($data, $res = false)
{
if (!isset($data['folder_path']) && !isset($data['folder_id'])) {
$this->set_error('Neither folder path nor ID given');
return false;
}
if (isset($data['folder_path']) && !isset($data['folder_id'])) {
$data['folder_id'] = $this->IDX->get_folder_id_from_path($this->uid, $data['folder_path']);
}
$ID = $this->IDX->item_add($this->uid, $data['folder_id'], $data);
if (!isset($data['filed']) || !$data['filed']) {
if ($res && is_resource($res)) {
list ($folderpath, $filename) = $this->IDX->item_get_real_location($this->uid, $ID);
$path = $this->userroot.'/'.$folderpath.'/'.$filename;
if (!file_exists(dirname($path)) || !is_dir(dirname($path))) basics::create_dirtree(dirname($path));
$fh = fopen($path, 'w');
while (feof($res) && false !== ($line = fgets($res, 1024))) fputs($fh, $line);
fclose($fh);
$old_umask = umask(0);
chmod($path, $GLOBALS['_PM_']['core']['file_umask']);
umask($old_umask);
}
}
return $ID;
}
public function update_item($item, $params)
{
return $this->IDX->item_update($this->uid, $item, $params);
}
/**
* Quota related: Returns the number of folders, the given user has created.
* @return int $num Number of user defined local folders created
* @since 0.7.5
*/
public function quota_getfoldernum($stats = false)
{
return $this->IDX->quota_getfoldernum($this->uid, $stats);
}
/**
* Qutoa related: Returns the overall size of all mails this user has stored in his
* local folders (including the system folders, of course).
* @return int $size Size of all mails in bytes
* @since 0.7.5
*/
public function quota_getitemsize($stats = false)
{
return $this->IDX->quota_getitemsize($this->uid, $stats);
}
/**
* Qutoa related: Returns the number of all mails this user has stored in his
* local folders (including the system folders, of course).
* @return int $size Number of all mails
* @since 0.7.5
*/
public function quota_getitemnum($stats = false)
{
return $this->IDX->quota_getitemnum($this->uid, $stats);
}
private function translate($return, $language)
{
foreach ($return as $k => $v) {
if (in_array($v['type'], array(0, 10, 20))) {
foreach ($this->sysfolders as $name => $data) {
if ($v['icon'] == $data['icon']) {
$return[$k]['foldername'] = (isset($language[$data['msg']])) ? $language[$data['msg']] : $v['foldername'];
break;
}
}
}
if (is_array($v['subdirs'])) {
$return[$k]['subdirs'] = $this->translate($v['subdirs'], $language);
}
}
return $return;
}
private function structurize_folders($data, $parent_id = 0, $path = '')
{
// Not valid parent ID
if (!isset($data[$parent_id])) return false;
foreach ($data[$parent_id] as $k => $v) {
$return[$k]['path'] = $k;
$return[$k]['folder_path'] = $v['folder_path'];
$return[$k]['icon'] = $v['icon'];
$return[$k]['foldername'] = $v['friendly_name'];
$return[$k]['type'] = $v['type'];
$return[$k]['has_folders'] = $v['has_folders'];
$return[$k]['has_items'] = $v['has_items'];
$return[$k]['subscribed'] = $v['subscribed'];
if (isset($data[$k])) {
$return[$k]['subdirs'] = $this->structurize_folders($data, $k);
} else {
$return[$k]['subdirs'] = false;
}
}
return $this->translate($return, $GLOBALS['WP_msg']);
}
}
?>