Browse Source

Merge pull request #232 from Telaxus/testing

Testing
experimental
Janusz Tylek 2 years ago
committed by GitHub
parent
commit
afd77cf5ad
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
74 changed files with 592 additions and 2215 deletions
  1. +83
    -0
      Vagrantfile
  2. +2
    -2
      include/misc.php
  3. +188
    -443
      modules/Utils/Attachment/AttachmentCommon_0.php
  4. +16
    -58
      modules/Utils/Attachment/AttachmentInstall.php
  5. +9
    -103
      modules/Utils/Attachment/Attachment_0.php
  6. +129
    -0
      modules/Utils/Attachment/FileActionHandler.php
  7. +0
    -122
      modules/Utils/Attachment/attachments.js
  8. +0
    -37
      modules/Utils/Attachment/create_remote.php
  9. +6
    -0
      modules/Utils/Attachment/file.php
  10. +0
    -114
      modules/Utils/Attachment/get.php
  11. +0
    -82
      modules/Utils/Attachment/get_all.php
  12. +0
    -56
      modules/Utils/Attachment/get_remote.php
  13. +0
    -14
      modules/Utils/Attachment/js/lib/i18n/cs.js
  14. +0
    -12
      modules/Utils/Attachment/js/lib/i18n/da.js
  15. +0
    -24
      modules/Utils/Attachment/js/lib/i18n/de.js
  16. +0
    -14
      modules/Utils/Attachment/js/lib/i18n/el.js
  17. +0
    -25
      modules/Utils/Attachment/js/lib/i18n/es.js
  18. +0
    -33
      modules/Utils/Attachment/js/lib/i18n/et.js
  19. +0
    -37
      modules/Utils/Attachment/js/lib/i18n/fa.js
  20. +0
    -33
      modules/Utils/Attachment/js/lib/i18n/fi.js
  21. +0
    -35
      modules/Utils/Attachment/js/lib/i18n/fr-ca.js
  22. +0
    -25
      modules/Utils/Attachment/js/lib/i18n/fr.js
  23. +0
    -25
      modules/Utils/Attachment/js/lib/i18n/hr.js
  24. +0
    -33
      modules/Utils/Attachment/js/lib/i18n/hu.js
  25. +0
    -24
      modules/Utils/Attachment/js/lib/i18n/it.js
  26. +0
    -37
      modules/Utils/Attachment/js/lib/i18n/ja.js
  27. +0
    -36
      modules/Utils/Attachment/js/lib/i18n/ko.js
  28. +0
    -33
      modules/Utils/Attachment/js/lib/i18n/lv.js
  29. +0
    -21
      modules/Utils/Attachment/js/lib/i18n/nl.js
  30. +0
    -24
      modules/Utils/Attachment/js/lib/i18n/pl.js
  31. +0
    -35
      modules/Utils/Attachment/js/lib/i18n/pt-br.js
  32. +0
    -35
      modules/Utils/Attachment/js/lib/i18n/pt.js
  33. +0
    -24
      modules/Utils/Attachment/js/lib/i18n/ro.js
  34. +0
    -21
      modules/Utils/Attachment/js/lib/i18n/ru.js
  35. +0
    -14
      modules/Utils/Attachment/js/lib/i18n/sr.js
  36. +0
    -12
      modules/Utils/Attachment/js/lib/i18n/sv.js
  37. +0
    -177
      modules/Utils/Attachment/js/lib/jquery.plupload.queue/css/jquery.plupload.queue.css
  38. BIN
      modules/Utils/Attachment/js/lib/jquery.plupload.queue/img/backgrounds.gif
  39. BIN
      modules/Utils/Attachment/js/lib/jquery.plupload.queue/img/buttons-disabled.png
  40. BIN
      modules/Utils/Attachment/js/lib/jquery.plupload.queue/img/buttons.png
  41. BIN
      modules/Utils/Attachment/js/lib/jquery.plupload.queue/img/delete.gif
  42. BIN
      modules/Utils/Attachment/js/lib/jquery.plupload.queue/img/done.gif
  43. BIN
      modules/Utils/Attachment/js/lib/jquery.plupload.queue/img/error.gif
  44. BIN
      modules/Utils/Attachment/js/lib/jquery.plupload.queue/img/throbber.gif
  45. BIN
      modules/Utils/Attachment/js/lib/jquery.plupload.queue/img/transp50.png
  46. +0
    -1
      modules/Utils/Attachment/js/lib/jquery.plupload.queue/jquery.plupload.queue.js
  47. +0
    -147
      modules/Utils/Attachment/js/lib/jquery.ui.plupload/css/jquery.ui.plupload.css
  48. BIN
      modules/Utils/Attachment/js/lib/jquery.ui.plupload/img/plupload-bw.png
  49. BIN
      modules/Utils/Attachment/js/lib/jquery.ui.plupload/img/plupload.png
  50. +0
    -1
      modules/Utils/Attachment/js/lib/jquery.ui.plupload/jquery.ui.plupload.js
  51. +0
    -1
      modules/Utils/Attachment/js/lib/plupload.browserplus.js
  52. +0
    -1
      modules/Utils/Attachment/js/lib/plupload.flash.js
  53. BIN
      modules/Utils/Attachment/js/lib/plupload.flash.swf
  54. +0
    -2
      modules/Utils/Attachment/js/lib/plupload.full.js
  55. +0
    -1
      modules/Utils/Attachment/js/lib/plupload.gears.js
  56. +0
    -1
      modules/Utils/Attachment/js/lib/plupload.html4.js
  57. +0
    -1
      modules/Utils/Attachment/js/lib/plupload.html5.js
  58. +0
    -2
      modules/Utils/Attachment/js/lib/plupload.js
  59. +0
    -1
      modules/Utils/Attachment/js/lib/plupload.silverlight.js
  60. BIN
      modules/Utils/Attachment/js/lib/plupload.silverlight.xap
  61. +0
    -41
      modules/Utils/Attachment/paste.php
  62. +43
    -0
      modules/Utils/Attachment/patches/20171024_use_generic_file_field.php
  63. +39
    -0
      modules/Utils/Attachment/patches/20171025_use_generic_attached_to_field.php
  64. +0
    -20
      modules/Utils/Attachment/remote.js
  65. +1
    -17
      modules/Utils/Attachment/theme/View_entry.tpl
  66. +1
    -1
      modules/Utils/Attachment/theme/browse.css
  67. +0
    -147
      modules/Utils/Attachment/upload.php
  68. +3
    -3
      modules/Utils/FileStorage/ActionHandler.php
  69. +1
    -0
      modules/Utils/FileStorage/FileLeightbox.php
  70. +8
    -1
      modules/Utils/FileStorage/FileStorageCommon_0.php
  71. +1
    -1
      modules/Utils/RecordBrowser/Access.php
  72. +26
    -4
      modules/Utils/RecordBrowser/RecordBrowserCommon_0.php
  73. +3
    -1
      modules/Utils/RecordBrowser/RecordBrowser_0.php
  74. +33
    -0
      playbook.yml

+ 83
- 0
Vagrantfile View File

@@ -0,0 +1,83 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.

# Every Vagrant development environment requires a box. You can search for
# boxes at https://vagrantcloud.com/search.
config.vm.box = "ubuntu/trusty64"

# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. This is not recommended.
# config.vm.box_check_update = false

# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
# NOTE: This will enable public access to the opened port
# config.vm.network "forwarded_port", guest: 80, host: 8080

# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine and only allow access
# via 127.0.0.1 to disable public access
# config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

# Create a private network, which allows host-only access to the machine
# using a specific IP.
config.vm.network "private_network", type: "dhcp"

# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
# config.vm.network "public_network"

# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
# config.vm.synced_folder "../data", "/vagrant_data"
config.vm.synced_folder ".", "/var/www/epesi", owner: "www-data", group: "www-data"
config.vm.synced_folder ".", "/vagrant"

# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
# Example for VirtualBox:
#
# config.vm.provider "virtualbox" do |vb|
# # Display the VirtualBox GUI when booting the machine
# vb.gui = true
#
# # Customize the amount of memory on the VM:
# vb.memory = "1024"
# end
#
# View the documentation for the provider you are using for more
# information on available options.

# Enable provisioning with a shell script. Additional provisioners such as
# Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
# documentation for more information about their specific syntax and use.
# config.vm.provision "shell", inline: <<-SHELL
# apt-get update
# apt-get install -y apache2
# SHELL

config.vm.provision "ansible_local" do |ansible|
ansible.playbook = "playbook.yml"
ansible.compatibility_mode = "2.0"
end

config.vm.provision "shell", privileged: false, inline: <<-EOF
echo "Congratulations! Vagrant machine is provisioned!"
echo "Now setup Your Epesi http://$(facter -p ipaddress_eth1)"
echo "Database credentials: admin:$(cat /vagrant/mysqlpassword)"
EOF
end

+ 2
- 2
include/misc.php View File

@@ -316,7 +316,7 @@ function recalculate_time($date,$time) {
function escapeJS($str,$double=true,$single=true) {return Epesi::escapeJS($str,$double,$single);}

function get_epesi_url() {
if(defined('EPESI_URL')) return rtrim(EPESI_URL,'/');
if(defined('EPESI_URL')) return rtrim(EPESI_URL,'/') . '/';
if(php_sapi_name() == 'cli')
return dirname(dirname(__FILE__));
$protocol = (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS'])!== "off") ? 'https://' : 'http://';
@@ -327,7 +327,7 @@ function get_epesi_url() {
$domain_name = $_SERVER['SERVER_NAME'];
}
$url = ($domain_name ? ($protocol . $domain_name) : '') . EPESI_DIR;
return trim($url);
return rtrim(trim($url), '/') . '/';
}

function get_client_ip_address()


+ 188
- 443
modules/Utils/Attachment/AttachmentCommon_0.php View File

@@ -39,9 +39,9 @@ class Utils_AttachmentCommon extends ModuleCommon {

public static function get_where($group,$group_starts_with=true) {
if($group_starts_with)
return DB::GetCol('SELECT attachment FROM utils_attachment_local WHERE local '.DB::like().' \''.DB::addq($group).'%\'');
return DB::GetCol('SELECT id FROM utils_attachment_data_1 WHERE f_attached_to '.DB::like().' \'\_\_'.DB::addq($group).'%\'');
else
return DB::GetCol('SELECT attachment FROM utils_attachment_local WHERE local='.DB::qstr($group));
return DB::GetCol('SELECT id FROM utils_attachment_data_1 WHERE f_attached_to='.DB::qstr('__' . $group. '__'));
}
/**
* Example usage:
@@ -52,36 +52,28 @@ class Utils_AttachmentCommon extends ModuleCommon {
if(isset($selective) && !empty($selective))
$ids = array_intersect($ids,$selective);
foreach($ids as $id) {
DB::StartTrans();
$mids = DB::GetCol('SELECT id FROM utils_attachment_file WHERE attach_id=%d',array($id));
foreach($mids as $mid) {
// at first we have to delete download as it references to file
DB::Execute('DELETE FROM utils_attachment_download WHERE attach_file_id=%d',array($mid));
// then file as it references filestorage id
DB::Execute('DELETE FROM utils_attachment_file WHERE id=%d',array($mid));
// finally filestorage link
Utils_FileStorageCommon::delete('attachment_file/'.$mid);
$note = self::get_note($id);
DB::StartTrans();
foreach($note['files'] as $fsid) {
Utils_FileStorageCommon::delete($fsid);
}
DB::Execute('DELETE FROM utils_attachment_local WHERE attachment=%d',array($id));
DB::CompleteTrans();
Utils_RecordBrowserCommon::delete_record('utils_attachment',$id,true);
}
}
public static function call_user_func_on_file($group,$func,$group_starts_with=false, $add_args=array()) {
$where = self::get_where($group,$group_starts_with);
if(!$where) return;
$ret = DB::Execute('SELECT f.id, f.original, f.created_on, f.attach_id as aid, f.filestorage_id as fsid
FROM utils_attachment_data_1 ual INNER JOIN utils_attachment_file f ON (f.attach_id=ual.id)
WHERE ual.active=1 AND f.deleted=0 AND ual.id IN ('.implode(',',$where).')');
while($row = $ret->FetchRow()) {
$id = $row['id'];
$local = $row['aid'];
try {
$meta = Utils_FileStorageCommon::meta($row['fsid']);
$file = $meta['file'];
call_user_func($func,$id,$file,$row['original'],$add_args,$row['created_on']);
} catch(Exception $e) {}
$ids = self::get_where($group,$group_starts_with);
if(!$ids) return;
foreach($ids as $id) {
$note = self::get_note($id);
foreach($note['files'] as $fsid) {
try {
$meta = Utils_FileStorageCommon::meta($fsid);
call_user_func($func,$id,$meta['file'],$meta['filename'],$add_args,$meta['created_on']);
} catch(Exception $e) {}
}
}
}

@@ -98,7 +90,7 @@ class Utils_AttachmentCommon extends ModuleCommon {
$details
);
if ($rid && $ret) {
$r = Utils_RecordBrowserCommon::get_record('utils_attachment', $rid);
$r = self::get_note($rid);
$of = Utils_RecordBrowserCommon::get_val('utils_attachment', 'attached_to', $r);
$ret['title'] .= " [ $of ]";
}
@@ -111,7 +103,7 @@ class Utils_AttachmentCommon extends ModuleCommon {

$old_user = Acl::get_user();
if($old_user!=$user) Acl::set_user($user);
$id = Utils_RecordBrowserCommon::new_record('utils_attachment',array('local'=>$group,'note'=>$note,'permission'=>$permission,'func'=>serialize($func),'args'=>serialize($args),'sticky'=>$sticky?1:0,'title'=>$note_title,'crypted'=>$crypted?1:0));
$id = Utils_RecordBrowserCommon::new_record('utils_attachment',array('attached_to'=>$group,'note'=>$note,'permission'=>$permission,'func'=>serialize($func),'args'=>serialize($args),'sticky'=>$sticky?1:0,'title'=>$note_title,'crypted'=>$crypted?1:0));
if($old_user!=$user) Acl::set_user($old_user);

if($file)
@@ -121,9 +113,14 @@ class Utils_AttachmentCommon extends ModuleCommon {
public static function add_file($note, $user, $oryg, $file) {
if($oryg===null) $oryg='';
$fsid = Utils_FileStorageCommon::write_file($oryg, $file, null, 'rb:utils_attachment/' . $note, null, $user);
DB::Execute('INSERT INTO utils_attachment_file(attach_id,original,created_by,filestorage_id) VALUES(%d,%s,%d,%d)',array($note,$oryg,$user,$fsid));
Utils_FileStorageCommon::add_link('attachment_file/'.DB::Insert_ID('utils_attachment_file','id'),$fsid);
$note = is_numeric($note)? self::get_note($note): $note;
if ($note['crypted']) {
if (isset($_SESSION['client']['cp'.$note['id']]))
file_put_contents($file,self::encrypt(file_get_contents($file),$_SESSION['client']['cp'.$note['id']]));
else trigger_error('Cannot add file to encrypted note', E_USER_ERROR);
}
$fsid = Utils_FileStorageCommon::write_file($oryg, $file, null, 'rb:utils_attachment/' . $note['id'], null, $user);
Utils_RecordBrowserCommon::update_record('utils_attachment', $note['id'], array('files' => array_merge($note['files'], array($fsid))));
@unlink($file);
}

@@ -144,125 +141,69 @@ class Utils_AttachmentCommon extends ModuleCommon {
}

public static function get_files($group=null,$group_starts_with=false) {
$where = self::get_where($group,$group_starts_with);
if(!$where) return array();
$sql = 'SELECT uaf.attach_id as note_id,' .
' uaf.id as file_id,' .
' uaf.created_by as upload_by,' .
' uaf.created_on as upload_on,' .
' uaf.original, uaf.filestorage_id,' .
' (SELECT count(*) FROM utils_attachment_download uad WHERE uaf.id=uad.attach_file_id) as downloads ' .
'FROM utils_attachment_file uaf INNER JOIN utils_attachment_data_1 note' .
' ON uaf.attach_id=note.id ' .
'WHERE note.id IN (' . implode(',', $where) . ') AND note.active=1 AND uaf.deleted=0';
return DB::GetAll($sql);
}

public static function search($word, $types)
{
$ret = array();
if (!$types) {
return $ret;
}

$r = null;
$limit = Base_SearchCommon::get_recordset_limit_records();

foreach ($types as $type) {
if ($type == 'files') {
$r = DB::SelectLimit('SELECT ua.id,uaf.original,ual.func,ual.args,ual.local,ua.f_title FROM utils_attachment_data_1 ua INNER JOIN utils_attachment_local AS ual ON ual.attachment=ua.id INNER JOIN utils_attachment_file AS uaf ON uaf.attach_id=ua.id WHERE ua.active=1 AND ' .
' uaf.original ' . DB::like() . ' ' . DB::Concat(DB::qstr('%'), '%s', DB::qstr('%')) . ' AND uaf.deleted=0', $limit, -1, array($word));
} elseif ($type == 'downloads') {
if (strlen($word) == 32) {
$query = 'SELECT ua.id,uaf.original,ual.func,ual.args,ual.local,ua.f_title FROM utils_attachment_file uaf INNER JOIN utils_attachment_download uad ON uad.attach_file_id=uaf.id INNER JOIN utils_attachment_data_1 ua ON uaf.attach_id=ua.id INNER JOIN utils_attachment_local AS ual ON ual.attachment=ua.id WHERE uad.token=' . DB::qstr($word);
$r = DB::Execute($query);
} else {
$query = parse_url($word, PHP_URL_QUERY);
if ($query) {
$vars = array();
parse_str($query, $vars);
if ($vars && isset($vars['id']) && isset($vars['token'])) {
$query = 'SELECT ua.id,uaf.original,ual.func,ual.args,ual.local,ua.f_title FROM utils_attachment_file uaf INNER JOIN utils_attachment_download uad ON uad.attach_file_id=uaf.id INNER JOIN utils_attachment_data_1 ua ON uaf.attach_id=ua.id INNER JOIN utils_attachment_local AS ual ON ual.attachment=ua.id WHERE uad.id=' . DB::qstr($vars['id']) . ' AND uad.token=' . DB::qstr($vars['token']);
$r = DB::Execute($query);
}
}
}
}

if ($r) {
while ($row = $r->FetchRow()) {
if (!self::get_access($row['id'])) {
continue;
}
$func = unserialize($row['func']);
$record = $func ? call_user_func_array($func, unserialize($row['args'])) : '';
if (!$record) {
continue;
}
$title = $row['original'] . ' - ' . self::description_callback(Utils_RecordBrowserCommon::get_record('utils_attachment', $row['id']));
$title = Utils_RecordBrowserCommon::record_link_open_tag('utils_attachment', $row['id'])
. __('Files') . ': ' . $title
. Utils_RecordBrowserCommon::record_link_close_tag();
$ret[$row['id'] . '#' . $row['local']] = $title . " ($record)";
}
}
}
return $ret;
}

public static function search_categories() {
return array('files'=>__('Files'),'downloads'=>Utils_TooltipCommon::create(__('Downloads'),__('Paste file download remote URL as "Keyword"')));
$ids = self::get_where($group,$group_starts_with);
if(!$ids) return array();
$files = array();
foreach($ids as $id) {
$note = self::get_note($id);
foreach($note['files'] as $fsid) {
$meta = Utils_FileStorageCommon::meta($fsid);
$files[] = array_merge($meta, $note, array(
'id' => $fsid,
'note_id' => $id,
'file_id' => null,
'upload_by' => $meta['created_by'],
'upload_on' => $meta['created_by'],
'original' => $meta['filename'],
'filestorage_id' => $fsid,
'downloads' => Utils_FileStorageCommon::get_downloads_count($fsid),
));
}
}
return $files;
}

public static function move_notes($to_group, $from_group) {
DB::Execute('UPDATE utils_attachment_local SET local=%s WHERE local=%s', array($to_group, $from_group));
public static function move_notes($to_group, $from_group, $notes = []) {
$notes = $notes?: self::get_where($from_group, false);
foreach ($notes as $note) {
if (!self::detach_note($note, $from_group)) continue;
self::attach_note($note, $to_group);
}
}

public static function copy_notes($from_group, $to_group) {
$notes = self::get_files($from_group);
$mapping = array();
foreach ($notes as $n) {
$meta = Utils_FileStorageCommon::meta($n['filestorage_id']);
$mapping[$n['note_id']] = @Utils_AttachmentCommon::add($to_group,$n['permission'],Acl::get_user(),$n['text'],$n['original'],$meta['file']);
$mapping[$n['note_id']] = @self::add($to_group,$n['permission'],Acl::get_user(),$n['text'],$n['original'],$n['file']);
}
return $mapping;
}
public static function detach_note($note, $group) {
$note = is_numeric($note)? self::get_note($note): $note;
if (($key = array_search($group, $note['attached_to'])) === false) return false;
unset($note['attached_to'][$key]);
DB::Execute('UPDATE utils_attachment_data_1 SET f_attached_to=%s WHERE id=%d',array(Utils_RecordBrowserCommon::encode_multi($note['attached_to']), $note['id']));
self::new_watchdog_event($group, '-', $note['id']);
return true;
}
public static function attach_note($note, $group) {
$note = is_numeric($note)? self::get_note($note): $note;
if (array_search($group, $note['attached_to']) !== false) return false;
$note['attached_to'][] = $group;
DB::Execute('UPDATE utils_attachment_data_1 SET f_attached_to=%s WHERE id=%d',array(Utils_RecordBrowserCommon::encode_multi($note['attached_to']), $note['id']));
self::new_watchdog_event($group, '+', $note['id']);
return true;
}
public static function is_image($note) {
if (!is_string($note)) $note = $note['original'];
return preg_match('/\.(jpg|jpeg|gif|png|bmp)$/i',$note);
}

public static function create_remote($file_id, $description, $expires_on) {
$r = DB::GetRow('SELECT id, token FROM utils_attachment_download WHERE remote=1 AND attach_file_id=%d AND expires_on>%T AND created_by=%d',array($file_id,time(),Acl::get_user()));
if (!empty($r)) {
$id = $r['id'];
$token = $r['token'];
} else {
$token = md5($file_id.$expires_on.mt_rand().$description);
DB::Execute('INSERT INTO utils_attachment_download(remote,attach_file_id,created_by,created_on,expires_on,description,token) VALUES (1,%d,%d,%T,%T,%s,%s)',array($file_id,Acl::get_user(),time(),$expires_on,$description,$token));
$id = DB::Insert_ID('utils_attachment_download','id');
}
return get_epesi_url().'/modules/Utils/Attachment/get_remote.php?'.http_build_query(array('id'=>$id,'token'=>$token));
}

public static function get_temp_dir() {
$targetDir = DATA_DIR.'/Utils_Attachment/temp/'.Acl::get_user();
if(!file_exists($targetDir))
mkdir($targetDir,0777,true);
return $targetDir;
}
public static function cleanup_paste_temp() {
DB::StartTrans();
$ret = DB::Execute('SELECT * FROM utils_attachment_clipboard WHERE created_on<=%T', array(date('Y-m-d H:i:s', strtotime('-1 day'))));
while ($row = $ret->FetchRow()) {
DB::Execute('DELETE FROM utils_attachment_clipboard WHERE id=%d', array($row['id']));
if ($row['filename']) @unlink($row['filename']);
}
DB::CompleteTrans();
}

public static function encrypt($input,$password, $hint = '') {
$iv = '';
$input .= md5($input);
@@ -283,27 +224,18 @@ class Utils_AttachmentCommon extends ModuleCommon {
const DECRYPT = 2;

public static function crypt($input,$password,$mode,& $iv=null) {
if(extension_loaded('mcrypt')) {
$td = mcrypt_module_open('rijndael-256', '', 'cbc', '');
if (!$iv && $mode === self::ENCRYPT) $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td));
$iv2 = $iv;
$ks = mcrypt_enc_get_key_size($td);
$key = substr(sha1($password), 0, $ks);
mcrypt_generic_init($td, $key, $iv2);
if ($mode == self::ENCRYPT)
$ret = mcrypt_generic($td, $input);
else
$ret = mdecrypt_generic($td, $input);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
} else {
if (!$iv && $mode === self::ENCRYPT) $iv = openssl_random_pseudo_bytes(16);
$key = openssl_pbkdf2($password, $iv, 16, 4096);
if ($mode == self::ENCRYPT)
$ret = openssl_encrypt($input, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
else
$ret = openssl_decrypt($input, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
}
$td = mcrypt_module_open('rijndael-256', '', 'cbc', '');
if(!$iv && $mode===self::ENCRYPT) $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td));
$iv2 = $iv;
$ks = mcrypt_enc_get_key_size($td);
$key = substr(sha1($password), 0, $ks);
mcrypt_generic_init($td, $key, $iv2);
if($mode==self::ENCRYPT)
$ret = mcrypt_generic($td, $input);
else
$ret = mdecrypt_generic($td, $input);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $ret;
}

@@ -317,53 +249,13 @@ class Utils_AttachmentCommon extends ModuleCommon {
}

public static function display_note($row, $nolink = false, $desc = null,$tab = null, $view = false) {
$inline_img = '';
$link_href = '';
$link_img = '';
$icon = '';
$crypted = Utils_RecordBrowserCommon::get_value('utils_attachment',$row['id'],'crypted');
if(!$crypted || isset($_SESSION['client']['cp'.$row['id']])) {
$files = DB::GetAll('SELECT id, created_by, created_on, original, filestorage_id, (SELECT count(*) FROM utils_attachment_download uad WHERE uaf.id=uad.attach_file_id) as downloads FROM utils_attachment_file uaf WHERE uaf.attach_id=%d AND uaf.deleted=0', array($row['id']));
foreach ($files as $f) {
if ($nolink) {
$icon .= '<br>' . $f['original'];
continue;
}
try {
$meta = Utils_FileStorageCommon::meta($f['filestorage_id']);
Utils_FileStorageCommon::file_exists($meta, true);
$f_filename = $meta['file'];
$filename = $f['original'];
$filetooltip = __('Filename: %s',array($filename)).'<br>'.__('File size: %s',array(filesize_hr($f_filename))).'<hr>'.
__('Last uploaded by %s', array(Base_UserCommon::get_user_label($f['created_by'], true))).'<br/>'.
__('On: %s',array(Base_RegionalSettingsCommon::time2reg($f['created_on']))).'<br/>'.
__('Number of downloads: %d',array($f['downloads']));
$view_link = '';
$lb = array();
$lb['aid'] = $row['id'];
$lb['crypted'] = $crypted;
$lb['original'] = $f['original'];
$lb['id'] = $f['id'];
$lb['filestorage_id'] = $f['filestorage_id'];
$link_href = Utils_TooltipCommon::open_tag_attrs($filetooltip).' '.self::get_file_leightbox($lb,$view_link);
$link_img = Base_ThemeCommon::get_template_file('Utils_Attachment','z-attach.png');
if(Utils_AttachmentCommon::is_image($filename) && $view_link)
$inline_img .= '<hr><a href="'.$view_link.'" target="_blank"><img src="'.$view_link.'" style="max-width:700px" /></a><br>';
} catch(Exception $e) {
$filename = __('Missing file: %s',array($f['original']));
$link_href = Utils_TooltipCommon::open_tag_attrs($filename);
$link_img = Base_ThemeCommon::get_template_file('Utils_Attachment','z-attach-off.png');
}
if ($link_href)
$icon .= '<div class="file_link"><a '.$link_href.'><img src="'.$link_img.'"><span class="file_name">'.$filename.'</span></a></div>';
}
}

if($crypted) {
$text = false;
if(isset($_SESSION['client']['cp'.$row['id']])) {
$note_pass = $_SESSION['client']['cp'.$row['id']];
$decoded = Utils_AttachmentCommon::decrypt($row['note'],$note_pass);
$decoded = self::decrypt($row['note'],$note_pass);
if($decoded!==false) {
$text = $decoded;
Utils_WatchdogCommon::notified('utils_attachment', $row['id']); // notified only when decrypted
@@ -373,8 +265,6 @@ class Utils_AttachmentCommon extends ModuleCommon {
$hint = self::get_password_hint($row['note']);
$hint = $hint ? ' (' . __('Hint: %s', array($hint)) . ')' : '';
$text = '<div id="note_value_'.$row['id'].'"><a href="javascript:void(0);" onclick="utils_attachment_password(\''.Epesi::escapeJS(__('Password').$hint.':').'\',\''.Epesi::escapeJS(__('OK')).'\','.$row['id'].')" style="color:red">'.__('Note encrypted').'</a></div>';
$icon = '';
$files = array();
} else {
$text = Utils_BBCodeCommon::parse($text);
}
@@ -390,33 +280,33 @@ class Utils_AttachmentCommon extends ModuleCommon {
self::$mark_as_read = array();
}

$text = (!$view?'<b style="float:left;margin-right:30px;">'.$row['title'].'</b> ':'').$text.$icon.$inline_img;
$text = (!$view?'<b style="float:left;margin-right:30px;">'.$row['title'].'</b> ':''). $text . self::display_files($row, $nolink);
if($row['sticky']) $text = '<img src="'.Base_ThemeCommon::get_template_file('Utils_Attachment','sticky.png').'" hspace=3 align="left"> '.$text;

return $text;
}

public static function display_attached_to($row, $nolink = false, $a=null,$view=false) {
$locals = DB::GetCol('SELECT local FROM utils_attachment_local WHERE attachment=%d',array($row['id']));
$ret = array();
foreach ($locals as $local) {
$param = explode('/', $local);
if (count($param) == 2 && preg_match('/^[1-9][0-9]*$/', $param[1])) {
if(!Utils_RecordBrowserCommon::check_table_name($param[0], false, false)) {
DB::Execute('DELETE FROM utils_attachment_local WHERE local=%s',array($local));
continue;
}
$label = Utils_RecordBrowserCommon::create_default_linked_label($param[0],$param[1],true);
$link =
Utils_RecordBrowserCommon::record_link_open_tag($param[0], $param[1], $nolink, 'view', array('switch_to_addon' => __('Notes')))
. $label . Utils_RecordBrowserCommon::record_link_close_tag();
$link = Utils_RecordBrowserCommon::create_default_record_tooltip_ajax($link, $param[0], $param[1]);
$ret[] = $link;
}
}
return implode(', ',$ret);
}
public static function display_files($row, $nolink = false, $desc = null, $tab = null) {
$crypted = Utils_RecordBrowserCommon::get_value('utils_attachment',$row['id'],'crypted');
if($crypted && !isset($_SESSION['client']['cp'.$row['id']])) return '';
$labels = [];
$inline_nodes = [];
$fileStorageIds = Utils_RecordBrowserCommon::decode_multi($row['files']);
$fileHandler = new Utils_Attachment_FileActionHandler();
foreach($fileStorageIds as $fileStorageId) {
if(!empty($fileStorageId)) {
$actions = $fileHandler->getActionUrlsAttachment($fileStorageId, 'utils_attachment', $row['id'], 'files', $row['crypted']);
$labels[]= Utils_FileStorageCommon::get_file_label($fileStorageId, $nolink, true, $actions);
$inline_nodes[]= Utils_FileStorageCommon::get_file_inline_node($fileStorageId, $actions);
}
}
$inline_nodes = array_filter($inline_nodes);
return implode('<br>', $labels) . ($inline_nodes? '<hr>': '') . implode('<hr>', $inline_nodes);
}

public static function description_callback($row,$nolink=false) {
if($row['title']) $ret = $row['title'];
elseif($row['crypted']) $ret = $row['id'].' ('.__('encrypted note').')';
@@ -429,7 +319,7 @@ class Utils_AttachmentCommon extends ModuleCommon {
}

public static function QFfield_note(&$form, $field, $label, $mode, $default, $desc, $rb_obj) {
load_js('modules/Utils/Attachment/attachments.js');
load_js(self::Instance()->get_module_dir() . 'attachments.js');

if($rb_obj->record['crypted']) {
if(!(isset($rb_obj->record['id']) && isset($_SESSION['client']['cp'.$rb_obj->record['id']])) && !(isset($rb_obj->record['clone_id']) && isset($_SESSION['client']['cp'.$rb_obj->record['clone_id']]))) {
@@ -449,7 +339,7 @@ class Utils_AttachmentCommon extends ModuleCommon {
$note_pass = $_SESSION['client']['cp'.$rb_obj->record['id']];
else
$note_pass = $_SESSION['client']['cp'.$rb_obj->record['clone_id']];
$decoded = Utils_AttachmentCommon::decrypt($default,$note_pass);
$decoded = self::decrypt($default,$note_pass);
if($decoded!==false) $default = $decoded;
else {
Epesi::alert(__('Note encrypted.'));
@@ -462,42 +352,24 @@ class Utils_AttachmentCommon extends ModuleCommon {
$fck = $form->addElement('ckeditor', $field, $label);
$fck->setFCKProps('99%','300',Base_User_SettingsCommon::get(self::Instance()->get_type(),'editor'));

load_js('modules/Utils/Attachment/js/lib/plupload.js');
load_js('modules/Utils/Attachment/js/lib/plupload.flash.js');
load_js('modules/Utils/Attachment/js/lib/plupload.browserplus.js');
load_js('modules/Utils/Attachment/js/lib/plupload.html4.js');
load_js('modules/Utils/Attachment/js/lib/plupload.html5.js');
if (!isset($_SESSION['client']['utils_attachment'][CID])) $_SESSION['client']['utils_attachment'][CID] = array('files'=>array());
eval_js('Utils_Attachment__init_uploader("'.floor(self::max_upload_size()/1024/1024).'mb")');
// eval_js('alert("'.self::max_upload_size().'")');
eval_js_once('var Utils_Attachment__delete_button = "'.Base_ThemeCommon::get_template_file('Utils_Attachment', 'delete.png').'";');
eval_js_once('var Utils_Attachment__restore_button = "'.Base_ThemeCommon::get_template_file('Utils_Attachment', 'restore.png').'";');
eval_js('Utils_Attachment__submit_note = function() {'.$form->get_submit_form_js().'}');

$del = $form->addElement('hidden', 'delete_files', null, array('id'=>'delete_files'));
$add = $form->addElement('hidden', 'clipboard_files', null, array('id'=>'clipboard_files'));

Libs_QuickFormCommon::add_on_submit_action('if(uploader.files.length){uploader.start();return;}');

if(isset($rb_obj->record['id']))
$files = DB::GetAssoc('SELECT id, original FROM utils_attachment_file uaf WHERE uaf.attach_id=%d AND uaf.deleted=0', array($rb_obj->record['id']));
elseif(isset($rb_obj->record['clone_id']))
$files = DB::GetAssoc('SELECT id, original FROM utils_attachment_file uaf WHERE uaf.attach_id=%d AND uaf.deleted=0', array($rb_obj->record['clone_id']));
else $files = array();
foreach($files as $id=>$name) {
eval_js('Utils_Attachment__add_file_to_list("'.Epesi::escapeJS($name,true,false).'", null, '.$id.');');
}

$form->setDefaults(array($field=>$default));
} else {
$form->addElement('static', $field, $label);
$form->setDefaults(array($field=>self::display_note($rb_obj->record,false,null,$rb_obj->tab,true)));
if(class_exists('ZipArchive')) {
$files = DB::GetOne('SELECT 1 FROM utils_attachment_file uaf WHERE uaf.attach_id=%d AND uaf.deleted=0', array($rb_obj->record['id']));
if($files) Base_ActionBarCommon::add('download','Download all attachments','href="'.self::Instance()->get_module_dir().'get_all.php?id='.$rb_obj->record['id'].'&cid='.CID.'" target="_blank"');
if($rb_obj->record['files']) {
$fileHandler = new Utils_Attachment_FileActionHandler();
$urls = $fileHandler->getActionUrlsAttachment(Utils_RecordBrowserCommon::decode_multi($rb_obj->record['files']), $rb_obj->tab, $rb_obj->record['id'], $field, $rb_obj->record['crypted']);
Base_ActionBarCommon::add('download', __('Download all attachments'), 'href="'.$urls['download'].'" target="_blank"');
}
}
}
}
public static function QFfield_files(&$form, $field, $label, $mode, $default, $desc, $rb_obj) {
if ($mode=='add' || $mode=='edit')
Utils_RecordBrowserCommon::QFfield_file($form, $field, $label, $mode, $default, $desc, $rb_obj);
}

public static function QFfield_crypted(&$form, $field, $label, $mode, $default, $desc, $rb_obj) {
if ($mode=='view') {
@@ -572,39 +444,45 @@ class Utils_AttachmentCommon extends ModuleCommon {
}
$crypted = 1;
}

//change of password
if(is_array($values['crypted']) && isset($values['crypted']['note_password']) && $mode=='edit' && $old_pass!=$values['crypted']['note_password']) {
//reencrypt old revisions
$old_notes = DB::GetAssoc('SELECT hd.edit_id,hd.old_value FROM utils_attachment_edit_history h INNER JOIN utils_attachment_edit_history_data hd ON h.id=hd.edit_id WHERE h.utils_attachment_id=%d AND hd.field="note"', array($values['id']));
foreach($old_notes as $old_id=>$old_note) {
if($old_pass!=='') $old_note = Utils_AttachmentCommon::decrypt($old_note,$old_pass);
if($old_pass!=='') $old_note = self::decrypt($old_note,$old_pass);
if($old_note===false) continue;
if($crypted && $values['crypted']['note_password']) $old_note = Utils_AttachmentCommon::encrypt($old_note,$values['crypted']['note_password'],$values['crypted']['note_password_hint']);
if($crypted && $values['crypted']['note_password']) $old_note = self::encrypt($old_note,$values['crypted']['note_password'],$values['crypted']['note_password_hint']);
if($old_note===false) continue;
DB::Execute('UPDATE utils_attachment_edit_history_data SET old_value=%s WHERE edit_id=%d AND field="note"',array($old_note,$old_id));
}
//file reencryption
$old_files = DB::GetAssoc('SELECT uaf.id as id, uaf.filestorage_id FROM utils_attachment_file uaf WHERE uaf.attach_id=%d',array($values['id']));
foreach($old_files as $id=>$fsid) {
try {
$meta = Utils_FileStorageCommon::meta($fsid);
} catch(Exception $e) { continue; }
$filename = $meta['file'];
$content = @file_get_contents($filename);
if($content===false) continue;
if($old_pass!=='') $content = Utils_AttachmentCommon::decrypt($content,$old_pass);
if($content===false) continue;
if($crypted && $values['crypted']['note_password']) $content = Utils_AttachmentCommon::encrypt($content,$values['crypted']['note_password'],$values['crypted']['note_password_hint']);
if($content===false) continue;
Utils_FileStorageCommon::set_content($fsid, $content);
//reencrypt old files
$old_files = self::get_all_files($values['id']);
foreach($old_files as $fsid) {
try {
$meta = Utils_FileStorageCommon::meta($fsid);
} catch(Exception $e) { continue; }
$content = @file_get_contents($meta['file']);
if($content===false) continue;
if($old_pass!=='') $content = self::decrypt($content,$old_pass);
if($content===false) continue;
if($crypted && $values['crypted']['note_password']) $content = self::encrypt($content,$values['crypted']['note_password'],$values['crypted']['note_password_hint']);
if($content===false) continue;
Utils_FileStorageCommon::set_content($fsid, $content);
}
}

if($crypted) {
if(is_array($values['crypted']) && isset($values['crypted']['note_password'])) {
$values['note'] = Utils_AttachmentCommon::encrypt($values['note'],$values['crypted']['note_password'],$values['crypted']['note_password_hint']);
$values['note'] = self::encrypt($values['note'],$values['crypted']['note_password'],$values['crypted']['note_password_hint']);
$values['note_password']=$values['crypted']['note_password'];
$values['note_password_hint'] = $values['crypted']['note_password_hint'];

foreach ($values['files'] as $file) {
//encrypt only newly uploaded files
if (!isset($file['file'])) continue;
file_put_contents($file['file'],self::encrypt(file_get_contents($file['file']),$values['note_password'], $values['note_password_hint']));
}
}
$values['crypted'] = 1;
} else {
@@ -617,21 +495,19 @@ class Utils_AttachmentCommon extends ModuleCommon {
$values['clone_id']=$values['id'];
break;
case 'added':
if(isset($values['local']))
DB::Execute('INSERT INTO utils_attachment_local(attachment,local,func,args) VALUES(%d,%s,%s,%s)',array($values['id'],$values['local'],$values['func'],$values['args']));
$new_values = $values;
break;
case 'edit_changes':
if(isset($values['note']) && isset($values['crypted']) && $new_values['crypted']!=$values['crypted']) {
if($new_values['crypted'] && isset($new_values['note_password'])) {
$values['note'] = Utils_AttachmentCommon::encrypt($values['note'],$new_values['note_password'], $new_values['note_password_hint']);
$values['note'] = self::encrypt($values['note'],$new_values['note_password'], $new_values['note_password_hint']);
} elseif(!$new_values['crypted'] && isset($_SESSION['client']['cp'.$new_values['id']])) {
$values['note'] = Utils_AttachmentCommon::decrypt($values['note'],$_SESSION['client']['cp'.$new_values['id']]);
$values['note'] = self::decrypt($values['note'],$_SESSION['client']['cp'.$new_values['id']]);
unset($_SESSION['client']['cp'.$new_values['id']]);
}
} elseif(isset($new_values['note_password']) && isset($old_password) && $new_values['note_password']!=$old_password) {
$values['note'] = Utils_AttachmentCommon::decrypt($values['note'],$old_password);
$values['note'] = Utils_AttachmentCommon::encrypt($values['note'],$new_values['note_password'],$new_values['note_password_hint']);
$values['note'] = self::decrypt($values['note'],$old_password);
$values['note'] = self::encrypt($values['note'],$new_values['note_password'],$new_values['note_password_hint']);
}
unset($values['edited_on']);
break;
@@ -640,7 +516,7 @@ class Utils_AttachmentCommon extends ModuleCommon {
if(!$ret) print(__('Access denied'));
return $ret;
case 'display':
if(DB::GetOne('SELECT 1 FROM utils_attachment_file WHERE attach_id=%d',array($values['id']))) {
if(self::get_all_files($values['id'])) {
$ret = array();
$ret['new'] = array();
$ret['new']['crm_filter'] = '<a '.Utils_TooltipCommon::open_tag_attrs(__('File history')).' '.Module::create_href(array('file_history'=>1)).'>F</a>';
@@ -655,14 +531,9 @@ class Utils_AttachmentCommon extends ModuleCommon {
Epesi::alert(__('Cannot delete encrypted note'));
return false;
}
$count_locals = DB::GetOne('SELECT count(DISTINCT local) FROM utils_attachment_local WHERE attachment=%d',array($values['id']));
if($count_locals>1) {
$is_local = false;
if(isset($_SESSION['client']['utils_attachment_group']))
$is_local = DB::GetOne('SELECT 1 FROM utils_attachment_local WHERE attachment=%d AND local=%s',array($values['id'],$_SESSION['client']['utils_attachment_group']));
if($is_local) {
DB::Execute('DELETE FROM utils_attachment_local WHERE attachment=%d AND local=%s',array($values['id'],$_SESSION['client']['utils_attachment_group']));
self::new_watchdog_event($_SESSION['client']['utils_attachment_group'], '-', $values['id']);
if(count($values['attached_to'])>1) {
if(isset($_SESSION['client']['utils_attachment_group'])) {
self::detach_note($values, $_SESSION['client']['utils_attachment_group']);
} else
Epesi::alert(__('This note is attached to multiple records - please go to record and delete note there.'));
location(array());
@@ -681,71 +552,27 @@ class Utils_AttachmentCommon extends ModuleCommon {
}

$note_id = $values['id'];
if(isset($values['delete_files']))
$deleted_files = array_filter(explode(';',$values['delete_files']));
else
$deleted_files = array();
foreach ($deleted_files as $k=>$v)
$deleted_files[$k] = intVal($v);
if($deleted_files) $deleted_files = array_combine($deleted_files,$deleted_files);
if($mode=='added' && isset($values['clone_id'])) { //on cloning
$locals = DB::Execute('SELECT local,func,args FROM utils_attachment_local WHERE attachment=%d',array($values['clone_id']));
while($local = $locals->FetchRow())
DB::Execute('INSERT INTO utils_attachment_local(attachment,local,func,args) VALUES(%d,%s,%s,%s)',array($note_id,$local['local'],$local['func'],$local['args']));
$clone_files = DB::GetAll('SELECT id,original,created_by,created_on,filestorage_id FROM utils_attachment_file uaf WHERE uaf.attach_id=%d AND uaf.deleted=0', array($values['clone_id']));
foreach($clone_files as $file) {
$fsid = $file['filestorage_id'];
$content = Utils_FileStorageCommon::read_content($fsid);
if(isset($_SESSION['client']['cp'.$values['clone_id']]) && $_SESSION['client']['cp'.$values['clone_id']])
$content = Utils_AttachmentCommon::decrypt($content,$_SESSION['client']['cp'.$values['clone_id']]);
if($values['crypted'])
$content = Utils_AttachmentCommon::encrypt($content,$values['note_password'],$new_values['note_password_hint']);
$fsid = Utils_FileStorageCommon::write_content($file['original'], $content, null, 'rb:utils_attachment/' . $note_id, $file['created_on'], $file['created_by']);
DB::Execute('INSERT INTO utils_attachment_file (attach_id,deleted,original,created_by,created_on,filestorage_id) VALUES(%d,0,%s,%d,%T,%d)',array($note_id,$file['original'],$file['created_by'],$file['created_on'],$fsid));
Utils_FileStorageCommon::add_link('attachment_file/'.DB::Insert_ID('utils_attachment_file','id'),$fsid);
}
}

$current_files = DB::GetAssoc('SELECT id, id FROM utils_attachment_file uaf WHERE uaf.attach_id=%d AND uaf.deleted=0', array($note_id));
$remaining_files = $current_files;
foreach ($deleted_files as $k=>$v) {
if (!isset($remaining_files[$v])) unset($deleted_files[$k]);
else unset($remaining_files[$v]);
}
foreach ($deleted_files as $v)
DB::Execute('UPDATE utils_attachment_file SET deleted=1 WHERE id=%d', array($v));

if(isset($values['clipboard_files'])) {
$clipboard_files = array_filter(explode(';',$values['clipboard_files']));
foreach ($clipboard_files as $cf_id) {
$cf = DB::GetOne('SELECT filename FROM utils_attachment_clipboard WHERE id=%d', array($cf_id));
if($values['crypted'])
file_put_contents($cf,Utils_AttachmentCommon::encrypt(file_get_contents($cf),$values['note_password'],$values['note_password_hint']));
Utils_AttachmentCommon::add_file($note_id, Acl::get_user(), __('clipboard').'.png', $cf);
if($mode=='added' && isset($values['clone_id'])) { //on cloning
$clone = self::get_note($values['clone_id']);
foreach($clone['files'] as $fsid) {
$meta = Utils_FileStorageCommon::meta($fsid);
$content = Utils_FileStorageCommon::read_content($fsid);
if(isset($_SESSION['client']['cp'.$values['clone_id']]) && $_SESSION['client']['cp'.$values['clone_id']])
$content = self::decrypt($content,$_SESSION['client']['cp'.$values['clone_id']]);
if($values['crypted'])
$content = self::encrypt($content,$values['note_password'],$new_values['note_password_hint']);
Utils_FileStorageCommon::write_content($meta['filename'], $content, null, 'rb:utils_attachment/' . $note_id, $meta['created_on'], $meta['created_by']);
}
}

$files = isset($_SESSION['client']['utils_attachment'][CID]['files'])?$_SESSION['client']['utils_attachment'][CID]['files']:array();
$_SESSION['client']['utils_attachment'][CID]['files'] = array();
foreach ($files as $f) {
$file_path = $f['path'];
$file_name = $f['name'];
if($values['crypted'])
file_put_contents($file_path,Utils_AttachmentCommon::encrypt(file_get_contents($file_path),$values['note_password'], $values['note_password_hint']));
Utils_AttachmentCommon::add_file($note_id, Acl::get_user(), $file_name, $file_path);
}

$locals = DB::GetCol('SELECT local FROM utils_attachment_local WHERE attachment=%d',array($note_id));
foreach ($locals as $local) {
$param = explode('/', $local);
if (count($param) == 2 && preg_match('/^[1-9][0-9]*$/', $param[1])) {
$subscribers = Utils_WatchdogCommon::get_subscribers($param[0], $param[1]);
foreach ($subscribers as $user_id) {
Utils_WatchdogCommon::user_subscribe($user_id, 'utils_attachment', $note_id);
}
foreach ($values['attached_to'] as $token) {
$token = Utils_RecordBrowserCommon::decode_record_token($token);
$subscribers = Utils_WatchdogCommon::get_subscribers($token['tab'], $token['id']);
foreach ($subscribers as $user_id) {
Utils_WatchdogCommon::user_subscribe($user_id, 'utils_attachment', $note_id);
}
}

@@ -754,116 +581,34 @@ class Utils_AttachmentCommon extends ModuleCommon {
return $values;
}
/**
* @param integer $id
* @return mixed - returns all fsids of all files associated with the record (including deleted ones)
*/
public static function get_all_files($id) {
return DB::GetCol('SELECT id FROM utils_filestorage WHERE backref=' . DB::qstr('rb:utils_attachment/' . $id) . ' OR backref ' . DB::like() . ' ' . DB::Concat(DB::qstr('rb:utils_attachment/' . $id .'/'), DB::qstr('%')));
}
public static function get_access($id) {
$locals = DB::GetCol('SELECT local FROM utils_attachment_local WHERE attachment=%d',array($id));
$note = self::get_note($id);
$ret = false;
foreach($locals as $local) {
list($recordset,$key) = explode('/',$local,2);
if(!Utils_RecordBrowserCommon::check_table_name($recordset, false, false)
|| !is_numeric($key)
|| Utils_RecordBrowserCommon::get_access($recordset,'view',$key)) {
foreach($note['attached_to'] as $token) {
$token = Utils_RecordBrowserCommon::decode_record_token($token);
if(!Utils_RecordBrowserCommon::check_table_name($token['tab'], false, false)
|| Utils_RecordBrowserCommon::get_access($token['tab'],'view',$token['id'])) {
$ret = true;
break;
}
}
return $ret;
}

public static function get_file_leightbox($row, & $view_link = '') {
static $th;
if(!isset($th)) $th = Base_ThemeCommon::init_smarty();

if($row['original']==='') return '';

$links = array();

$lid = 'get_file_'.md5(serialize($row));

$close_leightbox_js = 'leightbox_deactivate(\''.$lid.'\');';
$label = __('View');
$th->assign('save_options_id','');
$script = 'get';
$onclick = $close_leightbox_js;
$th->assign('download_options_id','attachment_download_options_'.$row['id']);

$view_link = 'modules/Utils/Attachment/'.$script.'.php?'.http_build_query(array('id'=>$row['id'],'cid'=>CID,'view'=>1));
$links['view'] = '<a href="'.$view_link.'" target="_blank" onClick="'.$onclick.'">'.$label.'</a><br>';
$links['download'] = '<a href="modules/Utils/Attachment/get.php?'.http_build_query(array('id'=>$row['id'],'cid'=>CID)).'" onClick="leightbox_deactivate(\''.$lid.'\')">'.__('Download').'</a><br>';
$file_history_key = md5(serialize($row['aid']));
if(isset($_GET['utils_attachment_file_history']) && $_GET['utils_attachment_file_history']==$file_history_key)
self::navigate_to_file_history($row['aid']);
$links['history'] = '<a onClick="'.Epesi::escapeJS(Module::create_href_js(array('utils_attachment_file_history'=>$file_history_key)),true,false).';leightbox_deactivate(\''.$lid.'\')">'.__('File History').'</a><br>';
load_js('modules/Utils/Attachment/remote.js');
if(!$row['crypted']) {
$links['link'] = '<a href="javascript:void(0)" onClick="utils_attachment_get_link('.$row['id'].', '.CID.',\'get link\');leightbox_deactivate(\''.$lid.'\')">'.__('Get link').'</a><br>';
}
$th->assign('filename',$row['original']);
$meta = Utils_FileStorageCommon::meta($row['filestorage_id']);
$f_filename = $meta['file'];
if(!file_exists($f_filename)) return 'missing file: '.$f_filename;
$th->assign('file_size',__('File size: %s',array(filesize_hr($f_filename))));

$th->assign('labels',array(
'filename'=>__('Filename'),
'file_size'=>__('File size')
));

foreach($links as $key=>&$l) {
$th->assign($key,$l);
$l = Base_ThemeCommon::parse_links($key, $l);
}
$th->assign('__link',$links);

$custom_getters = array();
if(!$row['crypted']) {
$getters = ModuleManager::call_common_methods('attachment_getters');
foreach($getters as $mod=>$arr) {
if (is_array($arr))
foreach($arr as $caption=>$func) {
$cus_id = md5($mod.$caption.serialize($func));
if(isset($_GET['utils_attachment_custom_getter']) && $_GET['utils_attachment_custom_getter']==$cus_id)
call_user_func_array(array($mod.'Common',$func['func']),array($f_filename,$row['original'],$row['id']));
$custom_getters[] = array('open'=>'<a href="javascript:void(0)" onClick="'.Epesi::escapeJS(Module::create_href_js(array('utils_attachment_custom_getter'=>$cus_id)),true,false).';leightbox_deactivate(\''.$lid.'\')">','close'=>'</a>','text'=>$caption,'icon'=>$func['icon']);
}
}
}
$th->assign('custom_getters',$custom_getters);

ob_start();
Base_ThemeCommon::display_smarty($th,'Utils_Attachment','download');
$c = ob_get_clean();

Libs_LeightboxCommon::display($lid,$c,__('Attachment'));
return Libs_LeightboxCommon::get_open_href($lid);
}
public static function navigate_to_file_history($attachment) {
$attachment = is_numeric($attachment)? Utils_RecordBrowserCommon::get_record('utils_attachment', $attachment): $attachment;
if ($attachment['crypted'] && !isset($_SESSION['client']['cp'.$attachment['id']]))
Epesi::alert(__('You have no access to this file history'));
else
Base_BoxCommon::push_module('Utils_Attachment','file_history',array($attachment));
}

//got from: http://www.kavoir.com/2010/02/php-get-the-file-uploading-limit-max-file-size-allowed-to-upload.html
private static function max_upload_size() {
$normalize = function($size) {
if (preg_match('/^([\d\.]+)([KMG])$/i', $size, $match)) {
$pos = array_search($match[2], array('K', 'M', 'G'));
if ($pos !== false) {
$size = $match[1] * pow(1024, $pos + 1);
}
}
return $size;
};
$max_upload = $normalize(ini_get('upload_max_filesize'));
$max_post = (ini_get('post_max_size') == 0) ?2*1024*1024: $normalize(ini_get('post_max_size'));
$memory_limit = (ini_get('memory_limit') == -1) ?$max_post : $normalize(ini_get('memory_limit'));
if($memory_limit < $max_post || $memory_limit < $max_upload) return $memory_limit;
if($max_post < $max_upload) return $max_post;
$maxFileSize = min($max_upload, $max_post, $memory_limit);
return $maxFileSize;
public static function get_note($id) {
static $cache;
if (!isset($cache[$id])) {
$cache[$id] = Utils_RecordBrowserCommon::get_record('utils_attachment', $id);
}
return $cache[$id];
}

/**


+ 16
- 58
modules/Utils/Attachment/AttachmentInstall.php View File

@@ -39,6 +39,13 @@ class Utils_AttachmentInstall extends ModuleInstall {
'display_callback'=>array('Utils_AttachmentCommon','display_note'),
'QFfield_callback'=>array('Utils_AttachmentCommon','QFfield_note'),
),
array('name' => _M('Files'),
'type' => 'file',
'required' => false,
'extra' => false,
'visible'=>false,
'QFfield_callback'=>array('Utils_AttachmentCommon','QFfield_files'),
),
array('name' => _M('Permission'),
'type' => 'commondata',
'required' => true,
@@ -52,10 +59,13 @@ class Utils_AttachmentInstall extends ModuleInstall {
'type' => 'checkbox',
'extra' => false,
'QFfield_callback'=>array('Utils_AttachmentCommon','QFfield_crypted')),
array('name' => _M('Attached to'),
'type' => 'calculated',
'extra' => false,
'display_callback'=>array('Utils_AttachmentCommon','display_attached_to')),
array('name' => _M('Attached to'),
'type' => 'multiselect',
'param' => '__RECORDSETS__::;',
'required' => false,
'extra' => false,
'visible'=>false,
),
);
Utils_RecordBrowserCommon::install_new_recordset('utils_attachment',$fields);
Utils_RecordBrowserCommon::add_access('utils_attachment', 'view', 'ACCESS:employee', array('(!permission'=>2, '|:Created_by'=>'USER_ID'));
@@ -72,56 +82,6 @@ class Utils_AttachmentInstall extends ModuleInstall {
Utils_RecordBrowserCommon::set_jump_to_id('utils_attachment', false);
Utils_RecordBrowserCommon::set_search('utils_attachment',1,0);

$ret &= DB::CreateTable('utils_attachment_local','
local C(255) NOTNULL,
attachment I4 NOTNULL,
func C(255),
args C(255)',
array('constraints'=>', FOREIGN KEY (attachment) REFERENCES utils_attachment_data_1(ID)'));
if(!$ret){
print('Unable to create table utils_attachment_local.<br>');
return false;
}
DB::CreateIndex('utils_attachment_local__idx', 'utils_attachment_local', 'local');

$ret &= DB::CreateTable('utils_attachment_file','
id I4 AUTO KEY NOTNULL,
attach_id I4 NOTNULL,
filestorage_id I8 NOTNULL,
original C(255) NOTNULL,
created_by I4,
created_on T DEFTIMESTAMP,
deleted I1 NOTNULL DEFAULT 0',
array('constraints'=>', FOREIGN KEY (created_by) REFERENCES user_login(ID), FOREIGN KEY (attach_id) REFERENCES utils_attachment_data_1(id), FOREIGN KEY (filestorage_id) REFERENCES utils_filestorage(id)'));
if(!$ret){
print('Unable to create table utils_attachment_file.<br>');
return false;
}
DB::CreateIndex('attach_id_idx','utils_attachment_file','attach_id');
$ret &= DB::CreateTable('utils_attachment_download','
id I4 AUTO KEY NOTNULL,
attach_file_id I4 NOTNULL,
created_by I4,
created_on T,
expires_on T,
remote I1 DEFAULT 0,
download_on T DEFTIMESTAMP,
ip_address C(32),
host_name C(64),
description C(128),
token C(32)',
array('constraints'=>', FOREIGN KEY (created_by) REFERENCES user_login(ID), FOREIGN KEY (attach_file_id) REFERENCES utils_attachment_file(id)'));
if(!$ret){
print('Unable to create table utils_attachment_download.<br>');
return false;
}
$ret &= DB::CreateTable('utils_attachment_clipboard','
id I4 AUTO KEY NOTNULL,
filename C(255),
created_by I4,
created_on T DEFTIMESTAMP',
array('constraints'=>''));

$this->create_data_dir();
file_put_contents($this->get_data_dir().'.htaccess','deny from all');
Base_ThemeCommon::install_default_theme($this->get_type());
@@ -134,9 +94,6 @@ class Utils_AttachmentInstall extends ModuleInstall {
Base_AclCommon::delete_permission('Attachments - view full download history');
$ret = true;

$ret &= DB::DropTable('utils_attachment_download');
$ret &= DB::DropTable('utils_attachment_file');
$ret &= DB::DropTable('utils_attachment_local');
Utils_RecordBrowserCommon::uninstall_recordset('utils_attachment');
Base_ThemeCommon::uninstall_default_theme($this->get_type());
return $ret;
@@ -147,7 +104,8 @@ class Utils_AttachmentInstall extends ModuleInstall {
}

public function requires($v) {
return array(array('name'=>Utils_GenericBrowserInstall::module_name(),'version'=>0),
return array(array('name'=>Utils_RecordBrowserInstall::module_name(),'version'=>0),
array('name'=>Utils_GenericBrowserInstall::module_name(),'version'=>0),
array('name'=>Utils_FileUploadInstall::module_name(), 'version'=>0),
array('name'=>Utils_FileStorageInstall::module_name(), 'version'=>0),
array('name'=>Utils_BBCodeInstall::module_name(), 'version'=>0),


+ 9
- 103
modules/Utils/Attachment/Attachment_0.php View File

@@ -59,7 +59,7 @@ class Utils_Attachment extends Module {
$_SESSION['client']['utils_attachment_group'] = $this->group;

load_js('modules/Utils/Attachment/attachments.js');
load_js($this->get_module_dir() . 'attachments.js');
Base_ThemeCommon::load_css('Utils_Attachment','browse');

$this->rb = $this->init_module(Utils_RecordBrowser::module_name(),'utils_attachment','utils_attachment');
@@ -68,13 +68,10 @@ class Utils_Attachment extends Module {
'func' => serialize($this->func),
'args' => serialize($this->args));
$rb_cols = array();
$single_group = (is_string($this->group) || count($this->group) == 1);
if ($this->force_multiple) {
$single_group = false;
}
$single_group = (is_string($this->group) || count($this->group) == 1) && !$this->force_multiple;
if ($single_group) {
$group = is_string($this->group) ? $this->group : reset($this->group);
$defaults['local'] = $group;
$defaults['attached_to'] = array($group);
} else {
// force attached to display
$rb_cols['attached_to'] = true;
@@ -94,7 +91,6 @@ class Utils_Attachment extends Module {
$this->rb->disable_actions(array('delete'));
$this->display_module($this->rb, array(array(':Created_by'=>$uid), $rb_cols, array('sticky'=>'DESC', 'edited_on'=>'DESC')), 'show_data');
} else {
$crits = array();
if(!is_array($this->group)) $this->group = array($this->group);

if(isset($_SESSION['attachment_copy']) && count($this->group)==1 && $_SESSION['attachment_copy']['group']!=$this->group) {
@@ -102,12 +98,11 @@ class Utils_Attachment extends Module {
Utils_TooltipCommon::open_tag_attrs($_SESSION['attachment_copy']['text']).' '.$this->create_callback_href(array($this,'paste'))
);
}
$crits = array(
'attached_to' => $this->group ?: 0
);

if($this->group) {
$g = array_map(array('DB','qstr'),$this->group);
$crits['id'] = DB::GetCol('SELECT attachment FROM utils_attachment_local WHERE local IN ('.implode(',',$g).')');
} else $crits['id'] = 0;
$this->display_module($this->rb, array($crits, $rb_cols, array('sticky'=>'DESC', 'edited_on'=>'DESC')), 'show_data');
$this->display_module($this->rb, array($crits, $rb_cols, array('sticky'=>'DESC', 'edited_on'=>'DESC')), 'show_data');
}
}

@@ -133,105 +128,16 @@ class Utils_Attachment extends Module {
public function paste() {
$group = reset($this->group);

if(DB::GetOne('SELECT 1 FROM utils_attachment_local WHERE attachment=%d AND local=%s',array($_SESSION['attachment_copy']['id'],$group))) return;
if (isset($_SESSION['attachment_cut']) && $_SESSION['attachment_cut']) {
$source_group = reset($_SESSION['attachment_copy']['group']);
DB::Execute('UPDATE utils_attachment_local SET local=%s,func=%s,args=%s WHERE attachment=%d AND local=%s', array($group, serialize($this->func), serialize($this->args), $_SESSION['attachment_copy']['id'], $source_group));
Utils_AttachmentCommon::new_watchdog_event($group, '+', $_SESSION['attachment_copy']['id']);
Utils_AttachmentCommon::new_watchdog_event($source_group, '-', $_SESSION['attachment_copy']['id']);
Utils_AttachmentCommon::move_notes($group, $source_group, [$_SESSION['attachment_copy']['id']]);
unset($_SESSION['attachment_cut']);
unset($_SESSION['attachment_copy']);
} else {
DB::Execute('INSERT INTO utils_attachment_local(local,attachment,func,args) VALUES(%s,%d,%s,%s)',array($group,$_SESSION['attachment_copy']['id'],serialize($this->func),serialize($this->args)));
Utils_AttachmentCommon::new_watchdog_event($group, '+', $_SESSION['attachment_copy']['id']);
Utils_AttachmentCommon::attach_note($_SESSION['attachment_copy']['id'], $group);
}
}

public function file_history($attachment) {
if($this->is_back()) {
return Base_BoxCommon::pop_main();
}

Base_ActionBarCommon::add('back',__('Back'),$this->create_back_href());

$file_leightbox_href = array();
$id = $attachment['id'];

$tb = $this->init_module(Utils_TabbedBrowser::module_name());
$tb->start_tab('File history');
$gb = $this->init_module(Utils_GenericBrowser::module_name(),null,'hua'.$id);
$gb->set_inline_display();
$gb->set_table_columns(array(
array('name'=>__('Deleted'), 'order'=>'deleted','width'=>10),
array('name'=>__('Date'), 'order'=>'upload_on','width'=>25),
array('name'=>__('Who'), 'order'=>'upload_by','width'=>25),
array('name'=>__('File'), 'order'=>'uaf.original')
));
$gb->set_default_order(array(__('Date')=>'DESC'));

$ret = $gb->query_order_limit('SELECT uaf.id,uaf.deleted,uaf.filestorage_id,uaf.created_on as upload_on,uaf.created_by as upload_by,uaf.original FROM utils_attachment_file uaf WHERE uaf.attach_id='.$id, 'SELECT count(*) FROM utils_attachment_file uaf WHERE uaf.attach_id='.$id);
while($row = $ret->FetchRow()) {
$r = $gb->get_new_row();
if ($row['deleted']) $r->add_action($this->create_confirm_callback_href(__('Are you sure you want to restore attached file?'),array($this,'restore_file'),array($row['id'])),'restore',__('Restore'));
$view_link = '';
$lb = array();
$lb['aid'] = $id;
$lb['crypted'] = $attachment['crypted'];
$lb['original'] = $row['original'];
$lb['id'] = $row['id'];
$lb['filestorage_id'] = $row['filestorage_id'];
$file_leightbox_href[$row['id']] = Utils_AttachmentCommon::get_file_leightbox($lb,$view_link);
$file = '<a '.$file_leightbox_href[$row['id']].'>'.$row['original'].'</a>';
$r->add_data($row['deleted']?__('Yes'):__('No'),Base_RegionalSettingsCommon::time2reg($row['upload_on']),Base_UserCommon::get_user_label($row['upload_by']),$file);
}
$this->display_module($gb);
$tb->end_tab();
$tb->start_tab('File access history');
$gb = $this->init_module(Utils_GenericBrowser::module_name(),null,'hda'.$id);
$gb->set_inline_display();
$gb->set_table_columns(array(
array('name'=>__('File'), 'order'=>'original','width'=>15),
array('name'=>__('Create date'), 'order'=>'created_on','width'=>15),
array('name'=>__('Download date'), 'order'=>'download_on','width'=>15),
array('name'=>__('Who'), 'order'=>'created_by','width'=>15),
array('name'=>__('IP Address'), 'order'=>'ip_address', 'width'=>15),
array('name'=>__('Host Name'), 'order'=>'host_name', 'width'=>15),
array('name'=>__('Method description'), 'order'=>'description', 'width'=>20),
array('name'=>__('Remote'), 'order'=>'remote', 'width'=>10),
));
$gb->set_default_order(array(__('Create date')=>'DESC'));

$query = 'SELECT uaf.id,uaf.original,uad.created_on,uad.download_on,(SELECT l.login FROM user_login l WHERE uad.created_by=l.id) as created_by,uad.remote,uad.ip_address,uad.host_name,uad.description FROM utils_attachment_download uad INNER JOIN utils_attachment_file uaf ON uaf.id=uad.attach_file_id WHERE uaf.attach_id='.$id;
$query_qty = 'SELECT count(*) FROM utils_attachment_download uad INNER JOIN utils_attachment_file uaf ON uaf.id=uad.attach_file_id WHERE uaf.attach_id='.$id;
if(Base_AclCommon::check_permission('Attachments - view full download history'))
$ret = $gb->query_order_limit($query, $query_qty);
else {
print('You are allowed to see your own downloads only');
$who = ' AND uad.created_by='.Acl::get_user();
$ret = $gb->query_order_limit($query.$who, $query_qty.$who);
}
while($row = $ret->FetchRow()) {
$r = $gb->get_new_row();
if (isset($file_leightbox_href[$row['id']]))
$file = '<a '.$file_leightbox_href[$row['id']].'>'.$row['original'].'</a>';
else
$file = $row['original'];
$r->add_data($file,Base_RegionalSettingsCommon::time2reg($row['created_on']),($row['remote']!=1?Base_RegionalSettingsCommon::time2reg($row['download_on']):''),$row['created_by'], $row['ip_address'], $row['host_name'], $row['description'], ($row['remote']==0?'no':'yes'));
}
$this->display_module($gb);
$tb->end_tab();
$this->display_module($tb);

$this->caption = 'Note history';

return true;
}

public function restore_file($id) {
DB::Execute('UPDATE utils_attachment_file SET deleted=0 WHERE id=%d',array($id));
return false;
}

public function caption() {
return $this->caption;
}


+ 129
- 0
modules/Utils/Attachment/FileActionHandler.php View File

@@ -0,0 +1,129 @@
<?php

require_once __DIR__ . '/../RecordBrowser/FileActionHandler.php';

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class Utils_Attachment_FileActionHandler
extends Utils_RecordBrowser_FileActionHandler
{
protected function getHandlingScript()
{
return 'modules/Utils/Attachment/file.php';
}

/**
* Get Action urls for RB file leightbox
*
* @param int $filestorageId Filestorage ID
* @param string $tab Recordset name. e.g. company
* @param int $recordId Record ID
* @param string $field Field identifier. e.g. company_name
* @param string $crypted If file is crypted or not
*
* @return array
*/
public function getActionUrlsAttachment($filestorageId, $tab, $recordId, $field, $crypted)
{
$params = ['tab' => $tab, 'record' => $recordId, 'field' => $field, 'crypted' => $crypted, 'cid' => CID];
return $this->getActionUrls($filestorageId, $params);
}
protected function hasAccess($action, $request)
{
$crypted = $request->get('crypted');
$recordId = $request->get('record');
if ($crypted && !isset($_SESSION['client']['cp'.$recordId]))
return false;
return parent::hasAccess($action, $request);
}
protected function getFile(Request $request, $disposition)
{
$filestorageId = $request->get('id');
$type = $request->get('action');
$crypted = $request->get('crypted');
$recordId = $request->get('record');
$filePack = is_array($filestorageId);
try {
$filestorageIds = is_array($filestorageId)? $filestorageId: array($filestorageId);
if ($filePack) {
$zipFilename = tempnam('tmp', 'zip');
$zip = new ZipArchive();
//create the file and throw the error if unsuccessful
if ($zip->open($zipFilename, ZIPARCHIVE::OVERWRITE )!==true)
throw new Utils_FileStorage_Exception("cannot open $zipFilename for writing - contact with administrator");
}
$size = 0;
foreach ($filestorageIds as $filestorageId) {
$meta = Utils_FileStorageCommon::meta($filestorageId);
$buffer = Utils_FileStorageCommon::read_content($filestorageId);
if($crypted) {
$buffer = Utils_AttachmentCommon::decrypt($buffer, $_SESSION['client']['cp'.$recordId]);
if ($buffer===false) throw new Utils_FileStorage_Exception('File decryption error');
}
$size += filesize($meta['file']);
@ini_set('memory_limit',ceil($size*2/1024/1024+64).'M');
if ($filePack)
$zip->addFromString($meta['filename'], $buffer);
}
if ($filePack)
$zip->close();
} catch (Utils_FileStorage_Exception $ex) {
if (Base_AclCommon::i_am_admin()) {
return new Response($ex->getMessage(), 400);
}
return false;
}
$type = self::actions[$type];
$time = time();
foreach ($filestorageIds as $filestorageId) {
$remote_address = get_client_ip_address();
$remote_host = gethostbyaddr($remote_address);
DB::Execute('INSERT INTO utils_filestorage_access(file_id,date_accessed,accessed_by,type,ip_address,host_name) '.
'VALUES (%d,%T,%d,%d,%s,%s)',array($filestorageId,$time,Acl::get_user()?Acl::get_user():0,$type,$remote_address,$remote_host));
}
$response = new Response();
if (!$filePack) {
$mime = Utils_FileStorageCommon::get_mime_type($meta['file'], $meta['filename']);
$response->setContent($buffer);
$response->headers->set('Content-Type', $mime);
$response->headers->set('Content-Length', strlen($buffer));
$response->headers->set('Content-Disposition', "$disposition; filename=\"$meta[filename]\"");
}
else {
ob_start();
$fp = fopen($zipFilename, 'rb');
while (!feof($fp)) {
print fread($fp, 1024);
}
fclose($fp);
@unlink($zipFilename);
$buffer = ob_get_clean();
$response->setContent($buffer);
$response->headers->set('Content-Type', 'application/zip');
$response->headers->set('Content-Length', strlen($buffer));
$response->headers->set('Content-Disposition', "attachment; filename=note_".$recordId.'.zip');
$response->headers->set('Pragma', 'no-cache');
$response->headers->set('Expires', '0');
}
return $response;
}
}

+ 0
- 122
modules/Utils/Attachment/attachments.js View File

@@ -1,125 +1,3 @@
var uploader;

Utils_Attachment__restore_existing = function (id) {
$('restore_existing_'+id).style.display="none";
$('delete_existing_'+id).style.display="";
$('existing_file_'+id).className = 'file';
var files = $('delete_files').value.split(';');
for (var i in files) {
if (files[i]==id) files.splice(i,1);
}
$('delete_files').value = files.join(';');
}

Utils_Attachment__delete_existing = function (id) {
$('restore_existing_'+id).style.display="";
$('delete_existing_'+id).style.display="none";
$('existing_file_'+id).className = 'file deleted';
$('delete_files').value = $('delete_files').value + ';' + id;
}

Utils_Attachment__delete_clipboard = function (id) {
var files = $('clipboard_files').value.split(';');
for (var i in files) {
if (files[i]==id) files.splice(i,1);
}
$('clipboard_files').value = files.join(';');
}

Utils_Attachment__add_clipboard = function (id) {
$('clipboard_files').value = $('clipboard_files').value + ';' + id;
}

Utils_Attachment__add_file_to_list = function (name, size, id, upload, clipboard) {
var button = '';
if (clipboard) {
Utils_Attachment__add_clipboard(id);
button = '<a href="javascript:void(0);" onclick="this.onclick=null;Utils_Attachment__delete_clipboard(\''+id+'\');Effect.Fade(\'clipboard_file_'+id+'\',{duration:0.5});"><img src="'+Utils_Attachment__delete_button+'" /></a>';
id = 'clipboard_file_'+id;
} else {
if (upload) {
button = '<a href="javascript:void(0);" onclick="this.onclick=null;uploader.removeFile(uploader.getFile(\''+id+'\'));Effect.Fade(\''+id+'\',{duration:0.5});"><img src="'+Utils_Attachment__delete_button+'" /></a>';
} else {
button = '<a href="javascript:void(0);" id="delete_existing_'+id+'" onclick="Utils_Attachment__delete_existing('+id+');"><img src="'+Utils_Attachment__delete_button+'" /></a>';
button += '<a href="javascript:void(0);" id="restore_existing_'+id+'" onclick="Utils_Attachment__restore_existing('+id+');" style="display:none;"><img src="'+Utils_Attachment__restore_button+'" /></a>';
id = 'existing_file_'+id;
}
}
$('filelist').innerHTML += '<div class="file" id="' + id + '"><div class="indicator">'+button+'</div><div class="filename">' + name + (size!=null?' (' + plupload.formatSize(size) + ')':'')+'</div></div>';
}

Utils_Attachment__init_uploader = function (max_fs) {
uploader = new plupload.Uploader({
runtimes : 'html5,flash',
browse_button : 'pickfiles',
container: 'multiple_attachments',
max_file_size : max_fs,
url : 'modules/Utils/Attachment/upload.php?CID='+Epesi.client_id,
//resize : {width : 320, height : 240, quality : 90},
preinit: uploader_attach_cb,
flash_swf_url : 'modules/Utils/Attachment/js/lib/plupload.flash.swf'
});

function uploader_attach_cb() {
uploader.bind('Error', function(up, e) {
alert(e.message);
});

uploader.bind('FilesAdded', function(up, files) {
files.each(function(s, i) {
Utils_Attachment__add_file_to_list(s.name, s.size, s.id, s);
});
});

uploader.bind('UploadProgress', function(up, file) {
$(file.id).getElementsByTagName('div')[0].innerHTML = '<b>' + file.percent + "%</b>";
});
uploader.bind('UploadComplete', function(up,files){
up.files.length = 0;
Utils_Attachment__submit_note();
});
uploader.bind('FileUploaded', function(up, file, response) {
response = response.response.evalJSON();
if (response.error != undefined && response.error.code){
alert(file.name+': '+response.error.message);
}
});
}

uploader.init();
}

document.onpaste = function(event) {
if (jq("#clipboard_files").length==0) return;
var items = event.clipboardData.items;
var s = JSON.stringify(items);
for (var i in items) {
if (items[i].type=='image/png') {
var blob = items[i].getAsFile();
var reader = new FileReader();
reader.onload = function(event) {
Epesi.procOn++;
Epesi.updateIndicator();
new Ajax.Request("modules/Utils/Attachment/paste.php", {
method: "post",
parameters:{
cid: Epesi.client_id,
data: event.target.result
},
onSuccess:function(t) {
Epesi.procOn--;
Epesi.updateIndicator();
var file = t.responseText.evalJSON();
Utils_Attachment__add_file_to_list(file.name, null, file.id, false, true);
}
});
};
reader.readAsDataURL(blob);
break;
}
}
}

utils_attachment_password = function(label,label_button,id,reload) {
var elem = jq('#note_value_'+id);
elem.html('<div>'+label+'<input type="password" id="attachment_pass_'+id+'" name="pass_'+id+'" style="max-width:200px"></input><input class="button" style="max-width:200px;height:auto;" type="button" value="'+label_button+'" id="attachment_submit_pass_'+id+'"/></div>');


+ 0
- 37
modules/Utils/Attachment/create_remote.php View File

@@ -1,37 +0,0 @@
<?php
/**
* Use this module if you want to add attachments to some page.
* @author Paul Bukowski <pbukowski@telaxus.com>
* @copyright Copyright &copy; 2008, Telaxus LLC
* @license MIT
* @version 1.0
* @package epesi-utils
* @subpackage attachment
*/
if(!isset($_REQUEST['cid']) || !isset($_REQUEST['file']))
die('Invalid usage');
$cid = $_REQUEST['cid'];
$id = $_REQUEST['file'];
if(isset($_REQUEST['description']))
$description = $_REQUEST['description'];
else
$description = '';

define('CID', $cid);
define('READ_ONLY_SESSION',true);
require_once('../../../include.php');
ModuleManager::load_modules();

if(!Acl::is_user())
die('Permission denied');
$file = DB::GetRow('SELECT uaf.attach_id, uaf.original FROM utils_attachment_file uaf WHERE uaf.id=%d',array($id));
$rec = Utils_RecordBrowserCommon::get_record('utils_attachment', $file['attach_id']);
if (!$rec) die('Invalid attachment.');
$access_fields = Utils_RecordBrowserCommon::get_access('utils_attachment', 'view', $rec);
if (!isset($access_fields['note']) || !$access_fields['note'])
die('Access forbidden');

$t = time()+3600*24*7;
print(Utils_AttachmentCommon::create_remote($id, $description, $t));

?>

+ 6
- 0
modules/Utils/Attachment/file.php View File

@@ -0,0 +1,6 @@
<?php

require_once __DIR__ . '/FileActionHandler.php';

$handler = new Utils_Attachment_FileActionHandler();
$handler->handle()->send();

+ 0
- 114
modules/Utils/Attachment/get.php View File

@@ -1,114 +0,0 @@
<?php
/**
* Use this module if you want to add attachments to some page.
* @author Paul Bukowski <pbukowski@telaxus.com>
* @copyright Copyright &copy; 2008, Telaxus LLC
* @license MIT
* @version 1.0
* @package epesi-utils
* @subpackage attachment
*/


if(!isset($_REQUEST['cid']) || !isset($_REQUEST['id']))
die('Invalid usage');
$cid = $_REQUEST['cid'];
$id = $_REQUEST['id'];
$disposition = (isset($_REQUEST['view']) && $_REQUEST['view'])?'inline':'attachment';

define('CID', $cid);
define('READ_ONLY_SESSION',true);
require_once('../../../include.php');
ModuleManager::load_modules();

if(!Acl::is_user())
die('Permission denied');
$file = DB::GetRow('SELECT uaf.attach_id, uaf.original, uaf.filestorage_id FROM utils_attachment_file uaf WHERE uaf.id=%d',array($id));
$rec = Utils_RecordBrowserCommon::get_record('utils_attachment', $file['attach_id']);
if (!$rec) die('Invalid attachment.');
$access_fields = Utils_RecordBrowserCommon::get_access('utils_attachment', 'view', $rec);
if (!isset($access_fields['note']) || !$access_fields['note'])
die('Access forbidden');

$original = $file['original'];
$local = $rec['id'];
$fsid = $file['filestorage_id'];
$crypted = $rec['crypted'];

$meta = Utils_FileStorageCommon::meta($fsid);

if(headers_sent())
die('Some data has already been output to browser, can\'t send file');

$password = '';
if($crypted)
$password = $_SESSION['client']['cp'.$rec['id']];

$t = time();
$remote_address = get_client_ip_address();
$remote_host = gethostbyaddr($remote_address);
DB::Execute('INSERT INTO utils_attachment_download(attach_file_id,created_by,created_on,download_on,description,ip_address,host_name) VALUES (%d,%d,%T,%T,%s,%s,%s)',array($id,Acl::get_user(),$t,$t,$disposition,$remote_address,$remote_host));

if (isset($_REQUEST['thumbnail'])) {
$o_filename = $meta['file'];
$f_filename = $o_filename.'_thumbnail';
if(!file_exists($f_filename)) {
if(!file_exists($o_filename))
die('File doesn\'t exists');
$image_info = getimagesize($o_filename);
$image_type = $image_info[2];
$image = false;
switch ($image_type) {
case IMAGETYPE_JPEG: $image = imagecreatefromjpeg($o_filename); break;
case IMAGETYPE_GIF: $image = imagecreatefromgif($o_filename); break;
case IMAGETYPE_PNG: $image = imagecreatefrompng($o_filename); break;
default: $buffer = file_get_contents($o_filename);
}
if ($image) {
$img_w = imagesx($image);
$img_h = imagesy($image);
$max = 300;
$w = ($img_w>=$img_h)?$max:floor($max*$img_w/$img_h);
$h = ($img_h>=$img_w)?$max:floor($max*$img_h/$img_w);
$new_image = imagecreatetruecolor($w, $h);
imagecopyresampled($new_image, $image, 0, 0, 0, 0, $w, $h, $img_w, $img_h);
switch ($image_type) {
case IMAGETYPE_JPEG: imagejpeg($new_image,$f_filename,95); break;
case IMAGETYPE_GIF: imagegif($new_image,$f_filename); break;
case IMAGETYPE_PNG: imagepng($new_image,$f_filename); break;
}
$buffer = file_get_contents($f_filename);
if($crypted) {
$buffer = Utils_AttachmentCommon::encrypt($buffer,$password);
file_put_contents($f_filename,$buffer);
}
}
} else {
$buffer = file_get_contents($f_filename);
}
} else {
$f_filename = $meta['file'];
if(!file_exists($f_filename))
die('File doesn\'t exists');
@ini_set('memory_limit',ceil(filesize($f_filename)*2/1024/1024+64).'M');
$buffer = file_get_contents($f_filename);
}

if($crypted) {
$buffer = Utils_AttachmentCommon::decrypt($buffer,$password);
if($buffer===false) die('Invalid attachment or password');
$mime = Utils_FileStorageCommon::get_mime_type(null, $original, $buffer);
} else {
$mime = Utils_FileStorageCommon::get_mime_type($f_filename, $original);
}

$expires = 24*60*60;
header('Pragma: public');
header('Cache-Control: maxage='.(24*60*60));
header('Expires: ' . gmdate('D, d M Y H:i:s', time()+(24*60*60)) . ' GMT');
header('Content-Type: '.$mime);
header('Content-Length: '.strlen($buffer));
header('Content-disposition: '.$disposition.'; filename="'.$original.'"');
echo $buffer;

?>

+ 0
- 82
modules/Utils/Attachment/get_all.php View File

@@ -1,82 +0,0 @@
<?php
/**
* Use this module if you want to add attachments to some page.
* @author Paul Bukowski <pbukowski@telaxus.com>
* @copyright Copyright &copy; 2008, Telaxus LLC
* @license MIT
* @version 1.0
* @package epesi-utils
* @subpackage attachment
*/

if(!isset($_REQUEST['cid']) || !isset($_REQUEST['id']))
die('Invalid usage');
$cid = $_REQUEST['cid'];
$id = $_REQUEST['id'];

define('CID', $cid);
define('READ_ONLY_SESSION',true);
require_once('../../../include.php');
ModuleManager::load_modules();

if(!Acl::is_user())
die('Permission denied');
$rec = Utils_RecordBrowserCommon::get_record('utils_attachment', $id);
if (!$rec) die('Invalid attachment.');
$access_fields = Utils_RecordBrowserCommon::get_access('utils_attachment', 'view', $rec);
if (!isset($access_fields['note']) || !$access_fields['note'])
die('Access forbidden');

$password = '';
$crypted = $rec['crypted'];
if($crypted)
$password = $_SESSION['client']['cp'.$rec['id']];
$files = DB::GetAssoc('SELECT id, original, filestorage_id FROM utils_attachment_file uaf WHERE uaf.attach_id=%d AND uaf.deleted=0', array($id));

$zip_filename = tempnam("tmp", "zip");

$zip = new ZipArchive();
//create the file and throw the error if unsuccessful
if ($zip->open($zip_filename, ZIPARCHIVE::OVERWRITE )!==TRUE) {
die("cannot open $zip_filename for writing - contact with administrator");
}
//add each files of $file_name array to archive
$t = time();
$remote_address = get_client_ip_address();
$remote_host = gethostbyaddr($remote_address);
$local = $rec['id'];
$size = 0;
foreach($files as $fid=>$row)
{
try {
$meta = Utils_FileStorageCommon::meta($row['filestorage_id']);
} catch(Exception $e) { continue; }
$f_filename = $meta['file'];
$size += filesize($f_filename);
@ini_set('memory_limit',ceil($size*2/1024/1024+64).'M');
$buffer = file_get_contents($f_filename);
if($crypted) {
$buffer = Utils_AttachmentCommon::decrypt($buffer,$password);
if($buffer===false) continue;
}
DB::Execute('INSERT INTO utils_attachment_download(attach_file_id,created_by,created_on,download_on,description,ip_address,host_name) VALUES (%d,%d,%T,%T,%s,%s,%s)',array($fid,Acl::get_user(),$t,$t,'zip',$remote_address,$remote_host));
$zip->addFromString($row['original'],$buffer);
}
$zip->close();

if(headers_sent())
die('Some data has already been output to browser, can\'t send file');

header("Content-type: application/zip");
header("Content-Length: " . filesize($zip_filename));
header("Content-Disposition: attachment; filename=note_".$id.'.zip');
header("Pragma: no-cache");
header("Expires: 0");
@ob_end_flush();
@flush();
$fp = fopen($zip_filename, 'rb');
while (!feof($fp)) {
print fread($fp, 1024);
}
fclose($fp);
@unlink($zip_filename);

+ 0
- 56
modules/Utils/Attachment/get_remote.php View File

@@ -1,56 +0,0 @@
<?php
/**
* Use this module if you want to add attachments to some page.
* @author Paul Bukowski <pbukowski@telaxus.com>
* @copyright Copyright &copy; 2008, Telaxus LLC
* @license MIT
* @version 1.0
* @package epesi-utils
* @subpackage attachment
*/
if(!isset($_REQUEST['token']) || !isset($_REQUEST['id']))
die('Invalid usage');
$id = $_REQUEST['id'];
$token = $_REQUEST['token'];

define('CID', false);
define('READ_ONLY_SESSION',true);
require_once('../../../include.php');
ModuleManager::load_modules();

$query = 'SELECT ual.id as aid,uaf.id,uaf.filestorage_id,uaf.attach_id,uaf.original,uad.ip_address,uad.attach_file_id,uad.created_by,uad.created_on,uad.description FROM (utils_attachment_file uaf INNER JOIN utils_attachment_download uad ON uad.attach_file_id=uaf.id) INNER JOIN utils_attachment_data_1 ual ON uaf.attach_id=ual.id WHERE uad.id='.DB::qstr($id).' AND uad.token='.DB::qstr($token).' AND uad.expires_on>'.DB::DBTimeStamp(time()).' AND uad.remote=';
$row = DB::GetRow($query.'1');
if($row==false) {
$row = DB::GetRow($query.'2');
if($row==false)
die('No such file');
$duplicate = true;
} else $duplicate = false;
$original = $row['original'];
$file_id = $row['id'];
$local = $row['aid'];
$fsid = $row['filestorage_id'];
$filename = $local.'/'.$file_id;

if(headers_sent())
die('Some data has already been output to browser, can\'t send file');

$t = time();
$remote_address = get_client_ip_address();
$remote_host = gethostbyaddr($remote_address);
if($duplicate)
DB::Execute('INSERT INTO utils_attachment_download(attach_file_id,created_by,created_on,download_on,description,ip_address,host_name,remote) VALUES (%d,%d,%T,%T,%s,%s,%s,2)',array($file_id,$row['created_by'],$row['created_on'],$t,$row['description'],$remote_address,$remote_host));
else
DB::Execute('UPDATE utils_attachment_download SET remote=2, download_on=%T, ip_address=%s, host_name=%s WHERE id=%d',array($t,$remote_address,$remote_host,$id));
$meta = Utils_FileStorageCommon::meta($fsid);
$f_filename = $meta['file'];
if(!file_exists($f_filename))
die('File doesn\'t exists');

@ini_set('memory_limit',ceil(filesize($f_filename)/1024/1024+64).'M');
$buffer = file_get_contents($f_filename);
header('Content-Type: '.Utils_FileStorageCommon::get_mime_type($f_filename,$original));
header('Content-Length: '.strlen($buffer));
header('Content-disposition: attachment; filename="'.$original.'"');
echo $buffer;
?>

+ 0
- 14
modules/Utils/Attachment/js/lib/i18n/cs.js View File

@@ -1,14 +0,0 @@
// .po file like language pack
plupload.addI18n({
'Select files' : 'Vyberte soubory',
'Add files to the upload queue and click the start button.' : 'Přidejte soubory do fronty a pak spusťte nahrávání.',
'Filename' : 'Název souboru',
'Status' : 'Status',
'Size' : 'Velikost',
'Add Files' : 'Přidat soubory',
'Stop current upload' : 'Zastavit nahrávání',
'Start uploading queue' : 'Spustit frontu nahrávání',
'Drag files here.' : 'Sem přetáhněte soubory.',
'Start Upload': 'Spustit nahrávání',
'Uploaded %d/%d files': 'Nahráno %d/%d souborů'
});

+ 0
- 12
modules/Utils/Attachment/js/lib/i18n/da.js View File

@@ -1,12 +0,0 @@
// .po file like language pack
plupload.addI18n({
'Select files' : 'Vælg filer',
'Add files to the upload queue and click the start button.' : 'Tilføj filer til køen, og tryk på start.',
'Filename' : 'Filnavn',
'Status' : 'Status',
'Size' : 'Størrelse',
'Add files' : 'Tilføj filer',
'Stop current upload' : 'Stop upload',
'Start uploading queue' : 'Start upload',
'Drag files here.' : 'Træk filer her.'
});

+ 0
- 24
modules/Utils/Attachment/js/lib/i18n/de.js View File

@@ -1,24 +0,0 @@
// German
plupload.addI18n({
'Select files' : 'Dateien hochladen',
'Add files to the upload queue and click the start button.' : 'Dateien hinzuf&uuml;gen und auf \'Hochladen\' klicken.',
'Filename' : 'Dateiname',
'Status' : 'Status',
'Size' : 'Gr&ouml;&szlig;e',
'Add files' : 'Dateien', // hinzuf&uuml;gen',
'Stop current upload' : 'Aktuelles Hochladen stoppen',
'Start uploading queue' : 'Hochladen starten',
'Uploaded %d/%d files': '%d/%d Dateien sind hochgeladen',
'N/A' : 'Nicht verf&uuml;gbar',
'Drag files here.' : 'Ziehen Sie die Dateien hier hin',
'File extension error.': 'Fehler bei Dateiendung',
'File size error.': 'Fehler bei Dateigr&ouml;ße',
'Init error.': 'Initialisierungsfehler',
'HTTP Error.': 'HTTP-Fehler',
'Security error.': 'Sicherheitsfehler',
'Generic error.': 'Typischer Fehler',
'IO error.': 'Ein/Ausgabe-Fehler',
'Stop Upload': 'Hochladen stoppen',
'Start upload': 'Hochladen',
'%d files queued': '%d Dateien in der Warteschlange'
});

+ 0
- 14
modules/Utils/Attachment/js/lib/i18n/el.js View File

@@ -1,14 +0,0 @@
// Greek
plupload.addI18n({
'Select files' : 'Επιλέξτε Αρχεία',
'Add files to the upload queue and click the start button.' : 'Προσθήκη αρχείων στην ουρά μεταφόρτωσης',
'Filename' : 'Όνομα αρχείου',
'Status' : 'Κατάσταση',
'Size' : 'Μέγεθος',
'Add Files' : 'Προσθέστε αρχεία',
'Stop current upload' : 'Διακοπή τρέχουσας μεταφόρτωσης',
'Start uploading queue' : 'Εκκίνηση μεταφόρτωσης ουράς αρχείων',
'Drag files here.' : 'Σύρετε αρχεία εδώ',
'Start Upload': 'Εκκίνηση μεταφόρτωσης',
'Uploaded %d/%d files': 'Ανέβηκαν %d/%d αρχεία'
});

+ 0
- 25
modules/Utils/Attachment/js/lib/i18n/es.js View File

@@ -1,25 +0,0 @@
// Spanish
plupload.addI18n({
'Select files' : 'Elija archivos:',
'Add files to the upload queue and click the start button.' : 'Agregue archivos a la cola de subida y haga click en el boton de iniciar.',
'Filename' : 'Nombre de archivo',
'Status' : 'Estado',
'Size' : 'Tama&ntilde;o',
'Add files' : 'Agregue archivos',
'Stop current upload' : 'Detener subida actual',
'Start uploading queue' : 'Iniciar subida de cola',
'Uploaded %d/%d files': 'Subidos %d/%d archivos',
'N/A' : 'No disponible',
'Drag files here.' : 'Arrastre archivos aqu&iacute;',
'File extension error.': 'Error de extensi&oacute;n de archivo.',
'File size error.': 'Error de tama&ntilde;o de archivo.',
'Init error.': 'Error de inicializaci&oacute;n.',
'HTTP Error.': 'Error de HTTP.',
'Security error.': 'Error de seguridad.',
'Generic error.': 'Error gen&eacute;rico.',
'IO error.': 'Error de entrada/salida.',
'Stop Upload': 'Detener Subida.',
'Add Files': 'Agregar Archivos',
'Start Upload': 'Comenzar Subida.',
'%d files queued': '%d archivos en cola.'
});

+ 0
- 33
modules/Utils/Attachment/js/lib/i18n/et.js View File

@@ -1,33 +0,0 @@
// Estonian translation, et.js
plupload.addI18n({
'Select files' : 'Vali faile',
'Add files to the upload queue and click the start button.' : 'Lisa failid üleslaadimise järjekorda ja klõpsa alustamise nupule.',
'Filename' : 'Failinimi',
'Status' : 'Olek',
'Size' : 'Suurus',
'Add files' : 'Lisa faile',
'Stop current upload' : 'Praeguse üleslaadimise peatamine',
'Start uploading queue' : 'Järjekorras ootavate failide üleslaadimise alustamine',
'Drag files here.' : 'Lohista failid siia.',
'Start upload' : 'Alusta üleslaadimist',
'Uploaded %d/%d files': 'Üles laaditud %d/%d',
'Stop upload': 'Peata üleslaadimine',
'Start upload': 'Alusta üleslaadimist',
'%d files queued': 'Järjekorras on %d faili',
'File: %s': 'Fail: %s',
'Close': 'Sulge',
'Using runtime: ': 'Kasutatakse varianti: ',
'File: %f, size: %s, max file size: %m': 'Fail: %f, suurus: %s, suurim failisuurus: %m',
'Upload element accepts only %d file(s) at a time. Extra files were stripped.': 'Üleslaadimise element saab vastu võtta ainult %d faili ühe korraga. Ülejäänud failid jäetakse laadimata.',
'Upload URL might be wrong or doesn\'t exist': 'Üleslaadimise URL võib olla vale või seda pole',
'Error: File too large: ': 'Viga: fail on liiga suur: ',