1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
16: class Ingo_Script_Imap extends Ingo_Script
17: {
18: 19: 20: 21: 22:
23: protected $_actions = array(
24: Ingo_Storage::ACTION_KEEP,
25: Ingo_Storage::ACTION_MOVE,
26: Ingo_Storage::ACTION_DISCARD,
27: Ingo_Storage::ACTION_MOVEKEEP
28: );
29:
30: 31: 32: 33: 34:
35: protected $_categories = array(
36: Ingo_Storage::ACTION_BLACKLIST,
37: Ingo_Storage::ACTION_WHITELIST
38: );
39:
40: 41: 42: 43: 44:
45: protected $_tests = array(
46: 'contains', 'not contain'
47: );
48:
49: 50: 51: 52: 53:
54: protected $_types = array(
55: Ingo_Storage::TYPE_HEADER,
56: Ingo_Storage::TYPE_SIZE,
57: Ingo_Storage::TYPE_BODY
58: );
59:
60: 61: 62: 63: 64:
65: protected $_supportIMAPFlags = true;
66:
67: 68: 69: 70: 71:
72: protected $_supportStopScript = true;
73:
74: 75: 76: 77: 78: 79:
80: protected $_ondemand = true;
81:
82: 83: 84: 85: 86:
87: protected $_api;
88:
89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100:
101: public function perform($params)
102: {
103: if (empty($params['api'])) {
104: $this->_api = Ingo_Script_Imap_Api::factory('Live', $params);
105: } else {
106: $this->_api = &$params['api'];
107: }
108:
109:
110: $ignore_ids = array();
111:
112: 113: 114: 115:
116: $cache = $this->_api->getCache();
117: if (($cache !== false) && ($cache == $GLOBALS['session']->get('ingo', 'change'))) {
118: return true;
119: }
120:
121:
122: $filters = $GLOBALS['ingo_storage']->retrieve(Ingo_Storage::ACTION_FILTERS);
123:
124:
125: foreach ($filters->getFilterList() as $rule) {
126: 127:
128: if (!$this->_validRule($rule['action']) ||
129: !empty($rule['disable'])) {
130: continue;
131: }
132:
133: switch ($rule['action']) {
134: case Ingo_Storage::ACTION_BLACKLIST:
135: case Ingo_Storage::ACTION_WHITELIST:
136: $bl_folder = null;
137:
138: if ($rule['action'] == Ingo_Storage::ACTION_BLACKLIST) {
139: $blacklist = $GLOBALS['ingo_storage']->retrieve(Ingo_Storage::ACTION_BLACKLIST);
140: $addr = $blacklist->getBlacklist();
141: $bl_folder = $blacklist->getBlacklistFolder();
142: } else {
143: $whitelist = $GLOBALS['ingo_storage']->retrieve(Ingo_Storage::ACTION_WHITELIST);
144: $addr = $whitelist->getWhitelist();
145: }
146:
147:
148: if (empty($addr)) {
149: continue;
150: }
151:
152: $query = $this->_getQuery($params);
153: $or_ob = new Horde_Imap_Client_Search_Query();
154: foreach ($addr as $val) {
155: $ob = new Horde_Imap_Client_Search_Query();
156: $ob->headerText('from', $val);
157: $or_ob->orSearch(array($ob));
158: }
159: $query->andSearch(array($or_ob));
160: $indices = $this->_api->search($query);
161:
162: 163:
164: if (!$msgs = $this->_api->fetchEnvelope($indices)) {
165: continue;
166: }
167:
168: foreach ($msgs as $v) {
169: $from_addr = Horde_Mime_Address::bareAddress(Horde_Mime_Address::addrArray2String($v->getEnvelope()->from, array('charset' => 'UTF-8')));
170: $found = false;
171: foreach ($addr as $val) {
172: if (strtolower($from_addr) == strtolower($val)) {
173: $found = true;
174: break;
175: }
176: }
177: if (!$found) {
178: $indices = array_diff($indices, array($v->getUid()));
179: }
180: }
181:
182: if ($rule['action'] == Ingo_Storage::ACTION_BLACKLIST) {
183: $indices = array_diff($indices, $ignore_ids);
184: if (!empty($indices)) {
185: if (!empty($bl_folder)) {
186: $this->_api->moveMessages($indices, $bl_folder);
187: } else {
188: $this->_api->deleteMessages($indices);
189: }
190: $GLOBALS['notification']->push(sprintf(_("Filter activity: %s message(s) that matched the blacklist were deleted."), count($indices)), 'horde.message');
191: }
192: } else {
193: $ignore_ids = $indices;
194: }
195: break;
196:
197: case Ingo_Storage::ACTION_KEEP:
198: case Ingo_Storage::ACTION_MOVE:
199: case Ingo_Storage::ACTION_DISCARD:
200: $base_query = $this->_getQuery($params);
201: $query = new Horde_Imap_Client_Search_Query();
202:
203: foreach ($rule['conditions'] as $val) {
204: $ob = new Horde_Imap_Client_Search_Query();
205:
206: if (!empty($val['type']) &&
207: ($val['type'] == Ingo_Storage::TYPE_SIZE)) {
208: $ob->size($val['value'], ($val['match'] == 'greater than'));
209: } elseif (!empty($val['type']) &&
210: ($val['type'] == Ingo_Storage::TYPE_BODY)) {
211: $ob->text($val['value'], true, ($val['match'] == 'not contain'));
212: } else {
213: if (strpos($val['field'], ',') == false) {
214: $ob->headerText($val['field'], $val['value'], $val['match'] == 'not contain');
215: } else {
216: foreach (explode(',', $val['field']) as $header) {
217: $hdr_ob = new Horde_Imap_Client_Search_Query();
218: $hdr_ob->headerText($header, $val['value'], $val['match'] == 'not contain');
219: if ($val['match'] == 'contains') {
220: $ob->orSearch(array($hdr_ob));
221: } elseif ($val['match'] == 'not contain') {
222: $ob->andSearch(array($hdr_ob));
223: }
224: }
225: }
226: }
227:
228: if ($rule['combine'] == Ingo_Storage::COMBINE_ALL) {
229: $query->andSearch(array($ob));
230: } else {
231: $query->orSearch(array($ob));
232: }
233: }
234:
235: $base_query->andSearch(array($query));
236: $indices = $this->_api->search($base_query);
237:
238: if (($indices = array_diff($indices, $ignore_ids))) {
239: if ($rule['stop']) {
240: 241: 242:
243: $ignore_ids = array_unique($indices + $ignore_ids);
244: }
245:
246:
247: if (!empty($rule['flags']) &&
248: ($rule['action'] != Ingo_Storage::ACTION_DISCARD)) {
249: $flags = array();
250: if ($rule['flags'] & Ingo_Storage::FLAG_ANSWERED) {
251: $flags[] = '\\answered';
252: }
253: if ($rule['flags'] & Ingo_Storage::FLAG_DELETED) {
254: $flags[] = '\\deleted';
255: }
256: if ($rule['flags'] & Ingo_Storage::FLAG_FLAGGED) {
257: $flags[] = '\\flagged';
258: }
259: if ($rule['flags'] & Ingo_Storage::FLAG_SEEN) {
260: $flags[] = '\\seen';
261: }
262: $this->_api->setMessageFlags($indices, $flags);
263: }
264:
265: if ($rule['action'] == Ingo_Storage::ACTION_KEEP) {
266:
267: $ignore_ids = array_unique($indices + $ignore_ids);
268: } elseif ($rule['action'] == Ingo_Storage::ACTION_MOVE) {
269:
270: if ($params['show_filter_msg'] &&
271: !($fetch = $this->_api->fetchEnvelope($indices))) {
272: continue;
273: }
274:
275:
276: $this->_api->moveMessages($indices, $rule['action-value']);
277:
278:
279: if ($params['show_filter_msg']) {
280: foreach ($fetch as $msg) {
281: $envelope = $msg->getEnvelope();
282: $GLOBALS['notification']->push(
283: sprintf(_("Filter activity: The message \"%s\" from \"%s\" has been moved to the folder \"%s\"."),
284: !empty($envelope->subject) ? Horde_Mime::decode($envelope->subject, 'UTF-8') : _("[No Subject]"),
285: !empty($envelope->from) ? Horde_Mime_Address::addrArray2String($envelope->from, array('charset' => 'UTF-8')) : _("[No Sender]"),
286: Horde_String::convertCharset($rule['action-value'], 'UTF7-IMAP', 'UTF-8')),
287: 'horde.message');
288: }
289: } else {
290: $GLOBALS['notification']->push(sprintf(_("Filter activity: %s message(s) have been moved to the folder \"%s\"."),
291: count($indices),
292: Horde_String::convertCharset($rule['action-value'], 'UTF7-IMAP', 'UTF-8')), 'horde.message');
293: }
294: } elseif ($rule['action'] == Ingo_Storage::ACTION_DISCARD) {
295:
296: if ($params['show_filter_msg'] &&
297: !($fetch = $this->_api->fetchEnvelope($indices))) {
298: continue;
299: }
300:
301:
302: $this->_api->deleteMessages($indices);
303:
304:
305: if ($params['show_filter_msg']) {
306: foreach ($fetch as $msg) {
307: $envelope = $msg->getEnvelope();
308: $GLOBALS['notification']->push(
309: sprintf(_("Filter activity: The message \"%s\" from \"%s\" has been deleted."),
310: !empty($envelope->subject) ? Horde_Mime::decode($envelope->subject, 'UTF-8') : _("[No Subject]"),
311: !empty($envelope->from) ? Horde_Mime_Address::addrArray2String($envelope->from, array('charset' => 'UTF-8')) : _("[No Sender]")),
312: 'horde.message');
313: }
314: } else {
315: $GLOBALS['notification']->push(sprintf(_("Filter activity: %s message(s) have been deleted."), count($indices)), 'horde.message');
316: }
317: } elseif ($rule['action'] == Ingo_Storage::ACTION_MOVEKEEP) {
318:
319: $this->_api->copyMessages($indices,
320: $rule['action-value']);
321:
322:
323: if ($params['show_filter_msg']) {
324: if (!($fetch = $this->_api->fetchEnvelope($indices))) {
325: continue;
326: }
327: foreach ($fetch as $msg) {
328: $envelope = $msg->getEnvelope();
329: $GLOBALS['notification']->push(
330: sprintf(_("Filter activity: The message \"%s\" from \"%s\" has been copied to the folder \"%s\"."),
331: !empty($envelope->subject) ? Horde_Mime::decode($envelope->subject, 'UTF-8') : _("[No Subject]"),
332: !empty($envelope->from) ? Horde_Mime_Address::addrArray2String($envelope->from, array('charset' => 'UTF-8')) : _("[No Sender]"),
333: Horde_String::convertCharset($rule['action-value'], 'UTF7-IMAP', 'UTF-8')),
334: 'horde.message');
335: }
336: } else {
337: $GLOBALS['notification']->push(sprintf(_("Filter activity: %s message(s) have been copied to the folder \"%s\"."), count($indices), Horde_String::convertCharset($rule['action-value'], 'UTF7-IMAP', 'UTF-8')), 'horde.message');
338: }
339: }
340: }
341: break;
342: }
343: }
344:
345:
346: $this->_api->storeCache($GLOBALS['session']->get('ingo', 'change'));
347:
348: return true;
349: }
350:
351: 352: 353: 354: 355:
356: public function canApply()
357: {
358: if ($this->performAvailable() &&
359: $GLOBALS['registry']->hasMethod('mail/server')) {
360: try {
361: $server = $GLOBALS['registry']->call('mail/server');
362: return ($server['protocol'] == 'imap');
363: } catch (Horde_Exception $e) {
364: return false;
365: }
366: }
367:
368: return false;
369: }
370:
371: 372: 373: 374: 375:
376: public function apply()
377: {
378: return $this->canApply()
379: ? $this->perform(array('mailbox' => 'INBOX', 'filter_seen' => $GLOBALS['prefs']->getValue('filter_seen'), 'show_filter_msg' => $GLOBALS['prefs']->getValue('show_filter_msg')))
380: : false;
381: }
382:
383: 384: 385: 386: 387: 388: 389: 390:
391: protected function _getQuery($params)
392: {
393: $ob = new Horde_Imap_Client_Search_Query();
394: $ob->flag('\\deleted', false);
395: if ($params['filter_seen'] == Ingo_Script::FILTER_SEEN ||
396: $params['filter_seen'] == Ingo_Script::FILTER_UNSEEN) {
397: $ob->flag('\\seen', $params['filter_seen'] == Ingo_Script::FILTER_SEEN);
398: }
399:
400: return $ob;
401: }
402:
403: }
404: