1: <?php
2: /**
3: * This class contains all functions related to handling logging of responses
4: * to individual e-mail messages.
5: *
6: * Copyright 2003-2012 Horde LLC (http://www.horde.org/)
7: *
8: * See the enclosed file COPYING for license information (GPL). If you
9: * did not receive this file, see http://www.horde.org/licenses/gpl.
10: *
11: * @author Michael Slusarz <slusarz@horde.org>
12: * @category Horde
13: * @license http://www.horde.org/licenses/gpl GPL
14: * @package IMP
15: */
16: class IMP_Maillog
17: {
18: /* Log Actions. */
19: const FORWARD = 'forward';
20: const MDN = 'mdn';
21: const REDIRECT = 'redirect';
22: const REPLY = 'reply';
23: const REPLY_ALL = 'reply_all';
24: const REPLY_LIST = 'reply_list';
25:
26: /**
27: * Create a log entry.
28: *
29: * @param mixed $type Either an IMP_Compose:: constant or an
30: * IMP_Maillog:: constant.
31: * @param mixed $msg_ids Either a single Message-ID or an array of
32: * Message-IDs to log.
33: * @param string $data Any additional data to store. For forward and
34: * redirect this is the list of recipients the
35: * message was sent to. For mdn this is the
36: * MDN-type of the message that was sent.
37: */
38: static public function log($type, $msg_ids, $data = null)
39: {
40: $history = $GLOBALS['injector']->getInstance('Horde_History');
41:
42: if (!is_array($msg_ids)) {
43: $msg_ids = array($msg_ids);
44: }
45:
46: foreach ($msg_ids as $val) {
47: switch ($type) {
48: case IMP_Compose::FORWARD:
49: case IMP_Compose::FORWARD_ATTACH:
50: case IMP_Compose::FORWARD_BODY:
51: case IMP_Compose::FORWARD_BOTH:
52: $params = array(
53: 'action' => self::FORWARD,
54: 'recipients' => $data
55: );
56: break;
57:
58: case self::MDN:
59: $params = array(
60: 'action' => self::MDN,
61: 'type' => $data
62: );
63: break;
64:
65: case IMP_Compose::REDIRECT:
66: $params = array(
67: 'action' => self::REDIRECT,
68: 'recipients' => $data
69: );
70: break;
71:
72: case IMP_Compose::REPLY:
73: case IMP_Compose::REPLY_SENDER:
74: $params = array(
75: 'action' => self::REPLY
76: );
77: break;
78:
79: case IMP_Compose::REPLY_ALL:
80: $params = array(
81: 'action' => self::REPLY_ALL
82: );
83: break;
84:
85: case IMP_Compose::REPLY_LIST:
86: $params = array(
87: 'action' => self::REPLY_LIST
88: );
89: break;
90:
91: default:
92: $params = null;
93: break;
94: }
95:
96: if ($params) {
97: try {
98: $history->log(self::_getUniqueHistoryId($val), $params);
99: } catch (Exception $e) {
100: /* On error, log the error message only since informing the
101: * user is just a waste of time and a potential point of
102: * confusion, especially since they most likely don't even
103: * know the message is being logged. */
104: $entry = sprintf('Could not log message details to Horde_History. Error returned: %s', $e->getMessage());
105: Horde::logMessage($entry, 'ERR');
106: }
107: }
108: }
109: }
110:
111: /**
112: * Retrieve any history for the given Message-ID.
113: *
114: * @param string $msg_id The Message-ID of the message.
115: *
116: * @return Horde_History_Log The object containing the log information.
117: * @throws Horde_Exception
118: */
119: static public function getLog($msg_id)
120: {
121: return $GLOBALS['injector']->getInstance('Horde_History')->getHistory(self::_getUniqueHistoryId($msg_id));
122: }
123:
124: /**
125: * Determines if an MDN notification of a certain type has been sent
126: * previously for this message-ID.
127: *
128: * @param string $msg_id The Message-ID of the message.
129: * @param string $type The type of MDN.
130: *
131: * @return boolean True if a MDN has been sent for this message with
132: * the given type.
133: */
134: static public function sentMDN($msg_id, $type)
135: {
136: try {
137: $msg_history = self::getLog($msg_id);
138: } catch (Horde_Exception $e) {
139: return false;
140: }
141:
142: if ($msg_history) {
143: foreach ($msg_history as $entry) {
144: if (($entry['action'] == 'mdn') && ($entry['type'] == $type)) {
145: return true;
146: }
147: }
148: }
149:
150: return false;
151: }
152:
153: /**
154: * Retrieve any history for the given Message-ID and (optionally) display
155: * via the Horde notification system.
156: *
157: * @param string $msg_id The Message-ID of the message.
158: */
159: static public function displayLog($msg_id)
160: {
161: foreach (self::parseLog($msg_id) as $entry) {
162: $GLOBALS['notification']->push($entry['msg'], 'imp.' . $entry['action']);
163: }
164: }
165:
166: /**
167: * Returns log information for a message.
168: *
169: * @param string $msg_id The Message-ID of the message.
170: *
171: * @return array List of log information. Each element is an array with
172: * the following keys:
173: * - action: (string) The log action.
174: * - msg: (string) The log message.
175: */
176: static public function parseLog($msg_id)
177: {
178: try {
179: if (!$msg_history = self::getLog($msg_id)) {
180: return array();
181: }
182: } catch (Horde_Exception $e) {
183: return array();
184: }
185:
186: $df = $GLOBALS['prefs']->getValue('date_format');
187: $tf = $GLOBALS['prefs']->getValue('time_format');
188: $ret = array();
189:
190: foreach ($msg_history as $entry) {
191: $msg = null;
192:
193: if (isset($entry['desc'])) {
194: $msg = $entry['desc'];
195: } else {
196: switch ($entry['action']) {
197: case self::FORWARD:
198: $msg = sprintf(_("You forwarded this message on %%s to: %s."), $entry['recipients']);
199: break;
200:
201: case self::MDN:
202: /* We don't display 'mdn' log entries. */
203: break;
204:
205: case self::REDIRECT:
206: $msg = sprintf(_("You redirected this message to %s on %%s."), $entry['recipients']);
207: break;
208:
209: case self::REPLY:
210: $msg = _("You replied to this message on %s.");
211: break;
212:
213: case self::REPLY_ALL:
214: $msg = _("You replied to all recipients of this message on %s.");
215: break;
216:
217: case self::REPLY_LIST:
218: $msg = _("You replied to this message via the mailing list on %s.");
219: break;
220: }
221: }
222:
223: if ($msg) {
224: $ret[] = array(
225: 'action' => $entry['action'],
226: 'msg' => @sprintf($msg, strftime($df . ' ' . $tf, $entry['ts']))
227: );
228: }
229: }
230:
231: return $ret;
232: }
233:
234: /**
235: * Delete the log entries for a given list of Message-IDs.
236: *
237: * @param mixed $msg_ids Either a single Message-ID or an array
238: * of Message-IDs to delete.
239: */
240: static public function deleteLog($msg_ids)
241: {
242: if (!is_array($msg_ids)) {
243: $msg_ids = array($msg_ids);
244: }
245: $msg_ids = array_map(array('IMP_Maillog', '_getUniqueHistoryId'), $msg_ids);
246:
247: $GLOBALS['injector']->getInstance('Horde_History')->removeByNames($msg_ids);
248: }
249:
250: /**
251: * Generate the unique log ID for a forward/reply/redirect event.
252: *
253: * @param string $msgid The Message-ID of the original message.
254: *
255: * @return string The unique log ID to use with Horde_History::.
256: */
257: static protected function _getUniqueHistoryId($msgid)
258: {
259: if (is_array($msgid)) {
260: return '';
261: }
262:
263: return implode('.', array('imp', str_replace('.', '*', $GLOBALS['registry']->getAuth()), $msgid));
264: }
265:
266: }
267: