comparison plugins/filesystem_attachments/filesystem_attachments.php @ 0:4681f974d28b

vanilla 1.3.3 distro, I hope
author Charlie Root
date Thu, 04 Jan 2018 15:52:31 -0500
parents
children bf99236cc5cd
comparison
equal deleted inserted replaced
-1:000000000000 0:4681f974d28b
1 <?php
2 /**
3 * Filesystem Attachments
4 *
5 * This is a core plugin which provides basic, filesystem based
6 * attachment temporary file handling. This includes storing
7 * attachments of messages currently being composed, writing attachments
8 * to disk when drafts with attachments are re-opened and writing
9 * attachments to disk for inline display in current html compositions.
10 *
11 * Developers may wish to extend this class when creating attachment
12 * handler plugins:
13 * require_once('plugins/filesystem_attachments/filesystem_attachments.php');
14 * class myCustom_attachments extends filesystem_attachments
15 *
16 * @license GNU GPLv3+
17 * @author Ziba Scott <ziba@umich.edu>
18 * @author Thomas Bruederli <roundcube@gmail.com>
19 */
20 class filesystem_attachments extends rcube_plugin
21 {
22 public $task = '?(?!login).*';
23
24 function init()
25 {
26 // Save a newly uploaded attachment
27 $this->add_hook('attachment_upload', array($this, 'upload'));
28
29 // Save an attachment from a non-upload source (draft or forward)
30 $this->add_hook('attachment_save', array($this, 'save'));
31
32 // Remove an attachment from storage
33 $this->add_hook('attachment_delete', array($this, 'remove'));
34
35 // When composing an html message, image attachments may be shown
36 $this->add_hook('attachment_display', array($this, 'display'));
37
38 // Get the attachment from storage and place it on disk to be sent
39 $this->add_hook('attachment_get', array($this, 'get'));
40
41 // Delete all temp files associated with this user
42 $this->add_hook('attachments_cleanup', array($this, 'cleanup'));
43 $this->add_hook('session_destroy', array($this, 'cleanup'));
44 }
45
46 /**
47 * Save a newly uploaded attachment
48 */
49 function upload($args)
50 {
51 $args['status'] = false;
52 $group = $args['group'];
53 $rcmail = rcmail::get_instance();
54
55 // use common temp dir for file uploads
56 $temp_dir = $rcmail->config->get('temp_dir');
57 $tmpfname = tempnam($temp_dir, 'rcmAttmnt');
58
59 if (move_uploaded_file($args['path'], $tmpfname) && file_exists($tmpfname)) {
60 $args['id'] = $this->file_id();
61 $args['path'] = $tmpfname;
62 $args['status'] = true;
63 @chmod($tmpfname, 0600); // set correct permissions (#1488996)
64
65 // Note the file for later cleanup
66 $_SESSION['plugins']['filesystem_attachments'][$group][$args['id']] = $tmpfname;
67 }
68
69 return $args;
70 }
71
72 /**
73 * Save an attachment from a non-upload source (draft or forward)
74 */
75 function save($args)
76 {
77 $group = $args['group'];
78 $args['status'] = false;
79
80 if (!$args['path']) {
81 $rcmail = rcmail::get_instance();
82 $temp_dir = $rcmail->config->get('temp_dir');
83 $tmp_path = tempnam($temp_dir, 'rcmAttmnt');
84
85 if ($fp = fopen($tmp_path, 'w')) {
86 fwrite($fp, $args['data']);
87 fclose($fp);
88 $args['path'] = $tmp_path;
89 }
90 else {
91 return $args;
92 }
93 }
94
95 $args['id'] = $this->file_id();
96 $args['status'] = true;
97
98 // Note the file for later cleanup
99 $_SESSION['plugins']['filesystem_attachments'][$group][$args['id']] = $args['path'];
100
101 return $args;
102 }
103
104 /**
105 * Remove an attachment from storage
106 * This is triggered by the remove attachment button on the compose screen
107 */
108 function remove($args)
109 {
110 $args['status'] = @unlink($args['path']);
111 return $args;
112 }
113
114 /**
115 * When composing an html message, image attachments may be shown
116 * For this plugin, the file is already in place, just check for
117 * the existance of the proper metadata
118 */
119 function display($args)
120 {
121 $args['status'] = file_exists($args['path']);
122 return $args;
123 }
124
125 /**
126 * This attachment plugin doesn't require any steps to put the file
127 * on disk for use. This stub function is kept here to make this
128 * class handy as a parent class for other plugins which may need it.
129 */
130 function get($args)
131 {
132 return $args;
133 }
134
135 /**
136 * Delete all temp files associated with this user
137 */
138 function cleanup($args)
139 {
140 // $_SESSION['compose']['attachments'] is not a complete record of
141 // temporary files because loading a draft or starting a forward copies
142 // the file to disk, but does not make an entry in that array
143 if (is_array($_SESSION['plugins']['filesystem_attachments'])) {
144 foreach ($_SESSION['plugins']['filesystem_attachments'] as $group => $files) {
145 if ($args['group'] && $args['group'] != $group) {
146 continue;
147 }
148
149 foreach ((array)$files as $filename) {
150 if(file_exists($filename)) {
151 unlink($filename);
152 }
153 }
154
155 unset($_SESSION['plugins']['filesystem_attachments'][$group]);
156 }
157 }
158 return $args;
159 }
160
161 function file_id()
162 {
163 $userid = rcmail::get_instance()->user->ID;
164 list($usec, $sec) = explode(' ', microtime());
165 $id = preg_replace('/[^0-9]/', '', $userid . $sec . $usec);
166
167 // make sure the ID is really unique (#1489546)
168 while ($this->find_file_by_id($id)) {
169 // increment last four characters
170 $x = substr($id, -4) + 1;
171 $id = substr($id, 0, -4) . sprintf('%04d', ($x > 9999 ? $x - 9999 : $x));
172 }
173
174 return $id;
175 }
176
177 private function find_file_by_id($id)
178 {
179 foreach ((array) $_SESSION['plugins']['filesystem_attachments'] as $group => $files) {
180 if (isset($files[$id])) {
181 return true;
182 }
183 }
184 }
185 }