1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
13:
14: 15: 16: 17: 18: 19: 20: 21: 22:
23: class IMP_Compose_LinkedAttachment
24: {
25: 26: 27: 28: 29:
30: protected $_atc;
31:
32: 33: 34: 35: 36:
37: protected $_id;
38:
39: 40: 41: 42: 43:
44: protected $_user;
45:
46: 47: 48: 49: 50: 51: 52: 53: 54:
55: public function __construct($user, $id = null)
56: {
57: global $conf, $injector;
58:
59:
60: if (empty($conf['compose']['link_attachments'])) {
61: throw new IMP_Exception('Linked attachments are forbidden.');
62: }
63:
64: $this->_atc = $injector->getInstance('IMP_Factory_ComposeAtc')->create($user, $id);
65: $this->_id = $id;
66: $this->_user = $user;
67: }
68:
69: 70: 71: 72: 73:
74: public function sendData()
75: {
76: global $browser;
77:
78: if (!$this->_atc->exists()) {
79: throw new IMP_Exception(_("The linked attachment does not exist. It may have been deleted by the original sender or it may have expired."));
80: }
81:
82: $data = $this->_atc->read();
83:
84: $md = $this->_atc->getMetadata();
85: $browser->downloadHeaders($md->filename, $md->type, false, $data->length());
86:
87: while (!$data->eof()) {
88: echo $data->substring(0, 8192);
89: }
90: $data->close();
91: }
92:
93: 94: 95: 96: 97: 98: 99: 100:
101: public function delete($token)
102: {
103: if (empty($GLOBALS['conf']['compose']['link_attachments_notify']) ||
104: !($dtoken = $this->_getDeleteToken()) ||
105: ($dtoken != $token)) {
106: return false;
107: }
108:
109: $md = $this->_atc->getMetadata();
110:
111: try {
112: $this->_atc->delete();
113: } catch (Exception $e) {}
114:
115: $this->_atc->saveMetadata();
116:
117: return $md->filename;
118: }
119:
120: 121: 122: 123: 124: 125: 126: 127:
128: public function convert($ts, $file)
129: {
130: global $injector;
131:
132: $vfs = $injector->getInstance('Horde_Core_Factory_Vfs')->create();
133:
134:
135: $id = hash('sha1', $ts . '|' . $file);
136:
137:
138: $atc = $injector->getInstance('IMP_Factory_ComposeAtc')->create($this->_user, $id);
139:
140: $old_path = '.horde/imp/attachments/' . $ts;
141: if (!$vfs->exists($old_path, $file)) {
142: return;
143: }
144:
145: try {
146: $vfs->rename($old_path, $file, $atc::VFS_LINK_ATTACH_PATH, $id);
147: } catch (Exception $e) {
148: return;
149: }
150:
151: $d_id = null;
152: $notify = $file . '.notify';
153:
154: if ($vfs->exists($old_path, $notify)) {
155: try {
156: $d_id = $vfs->read($old_path, $notify);
157: $vfs->deleteFile($old_path, $notify);
158: } catch (Exception $e) {}
159: }
160:
161: $md = $atc->getMetadata();
162: $md->dtoken = $d_id;
163: $md->filename = $file;
164: $md->time = $ts;
165: $md->type = 'application/octet-stream';
166: $atc->saveMetadata($md);
167:
168: $this->_atc = $atc;
169: $this->_id = $id;
170: }
171:
172: 173: 174:
175: public function sendNotification()
176: {
177: global $conf, $injector, $registry;
178:
179: if (empty($conf['compose']['link_attachments_notify'])) {
180: return;
181: }
182:
183: try {
184: $identity = $injector->getInstance('Horde_Core_Factory_Identity')->create($this->_user);
185: $address = $identity->getDefaultFromAddress();
186:
187:
188: if ((strlen($address) < 3) || $this->_getDeleteToken()) {
189: return;
190: }
191:
192: $address_full = $identity->getDefaultFromAddress(true);
193:
194:
195: if (!$registry->getAuth()) {
196: $prefs = $injector->getInstance('Horde_Core_Factory_Prefs')
197: ->create('imp', array('user' => $this->_user));
198: $registry->setLanguageEnvironment($prefs->getValue('language'));
199: }
200:
201: $h = new Horde_Mime_Headers();
202: $h->addReceivedHeader(array(
203: 'dns' => $injector->getInstance('Net_DNS2_Resolver'),
204: 'server' => $conf['server']['name']
205: ));
206: $h->addMessageIdHeader();
207: $h->addUserAgentHeader();
208: $h->addHeader('Date', date('r'));
209: $h->addHeader('From', $address_full);
210: $h->addHeader('To', $address_full);
211: $h->addHeader('Subject', _("Notification: Linked attachment downloaded"));
212: $h->addHeader('Auto-Submitted', 'auto-generated');
213:
214: $msg = new Horde_Mime_Part();
215: $msg->setType('text/plain');
216: $msg->setCharset('UTF-8');
217:
218: $md = $this->_atc->getMetadata();
219: $msg->setContents(Horde_String::wrap(
220: _("Your linked attachment has been downloaded by at least one user.") . "\n\n" .
221: sprintf(_("Name: %s"), $md->filename) . "\n" .
222: sprintf(_("Type: %s"), $md->type) . "\n" .
223: sprintf(_("Sent Date: %s"), date('r', $md->time)) . "\n\n" .
224: _("Click on the following link to permanently delete the attachment:") . "\n" .
225: strval($this->_atc->link_url->add('d', $this->_getDeleteToken(true)))
226: ));
227:
228: $msg->send($address, $h, $injector->getInstance('Horde_Mail'));
229: } catch (Exception $e) {
230: Horde::log($e, 'ERR');
231: }
232: }
233:
234:
235:
236: 237: 238: 239: 240: 241: 242: 243: 244: 245:
246: public static function keepDate($past = true)
247: {
248: return ($damk = $GLOBALS['prefs']->getValue('delete_attachments_monthly_keep'))
249: ? mktime(0, 0, 0, date('n') + ($past ? ($damk * -1) : ($damk + 1)), 1, date('Y'))
250: : null;
251: }
252:
253:
254:
255: 256: 257: 258: 259: 260: 261:
262: protected function _getDeleteToken($create = false)
263: {
264: $md = $this->_atc->getMetadata();
265:
266: if (is_null($md->dtoken)) {
267: if (!$create) {
268: return null;
269: }
270:
271: $md->dtoken = strval(new Horde_Support_Uuid);
272: try {
273: $this->_atc->saveMetadata($md);
274: } catch (Exception $e) {}
275: }
276:
277: return $md->dtoken;
278: }
279:
280: }
281: