Commit | Line | Data |
---|---|---|
7027794f | 1 | <?php |
2 | /******************************************************************************** | |
3 | * banana/message.inc.php : class for messages | |
4 | * ------------------------ | |
5 | * | |
6 | * This file is part of the banana distribution | |
7 | * Copyright: See COPYING files that comes with this distribution | |
8 | ********************************************************************************/ | |
9 | ||
10 | require_once dirname(__FILE__) . '/mimepart.inc.php'; | |
11 | require_once dirname(__FILE__) . '/message.func.inc.php'; | |
12 | require_once dirname(__FILE__) . '/banana.inc.php'; | |
13 | ||
14 | final class BananaMessage extends BananaMimePart | |
15 | { | |
16 | private $msg_headers = array(); | |
17 | ||
18 | public function __construct($data = null) | |
19 | { | |
20 | parent::__construct($data); | |
21 | if (!is_null($data)) { | |
22 | if (isset($this->headers['in-reply-to']) && isset($this->headers['references'])) { | |
23 | unset($this->headers['in-reply-to']); | |
24 | } | |
e9360b11 | 25 | Banana::$msgshow_headers = array_intersect(Banana::$msgshow_headers, array_keys($this->headers)); |
7027794f | 26 | Banana::$message =& $this; |
27 | } | |
28 | } | |
29 | ||
30 | public function hasHeader($hdr) | |
31 | { | |
32 | return isset($this->headers[$hdr]); | |
33 | } | |
34 | ||
35 | static public function newMessage(array $headers, $body, array $file = null) | |
36 | { | |
37 | $msg = new BananaMessage(); | |
38 | $msg->msg_headers = $headers; | |
168e9acb | 39 | $msg->makeTextPart($body, 'text/plain', '8bits', 'UTF-8', 'flowed'); |
7027794f | 40 | if (!is_null($file)) { |
41 | $msg->addAttachment($file); | |
42 | } | |
43 | return $msg; | |
44 | } | |
45 | ||
46 | static public function translateHeaderName($hdr) | |
47 | { | |
48 | switch (strtolower($hdr)) { | |
49 | case 'from': return _b_('De'); | |
50 | case 'subject': return _b_('Sujet'); | |
51 | case 'newsgroups': return _b_('Forums'); | |
598a1c53 | 52 | case 'followup-to': return _b_('Suivi à'); |
53 | case 'to': return _b_('À'); | |
54 | case 'cc': return _b_('Copie à'); | |
55 | case 'bcc': return _b_('Copie cachée à'); | |
56 | case 'reply-to': return _b_('Répondre à'); | |
7027794f | 57 | case 'date': return _b_('Date'); |
58 | case 'organization': return _b_('Organisation'); | |
59 | case 'in-reply-to': | |
598a1c53 | 60 | case 'references': return _b_('Références'); |
7027794f | 61 | case 'x-face': return _b_('Image'); |
62 | } | |
63 | return $hdr; | |
64 | } | |
65 | ||
66 | public function translateHeaderValue($hdr) | |
67 | { | |
68 | if (!isset($this->headers[$hdr])) { | |
69 | return null; | |
70 | } | |
71 | $text = $this->headers[$hdr]; | |
72 | ||
73 | if (function_exists('hook_formatDisplayHeader') | |
74 | && $res = hook_formatDisplayHeader($hdr, $text)) { | |
75 | return $res; | |
76 | } | |
77 | switch ($hdr) { | |
78 | case "date": | |
79 | return BananaMessage::formatDate($text); | |
80 | ||
81 | case "followup-to": case "newsgroups": | |
82 | $groups = preg_split("/[\t ]*,[\t ]*/", $text); | |
83 | $res = ''; | |
84 | foreach ($groups as $g) { | |
85 | $res .= Banana::$page->makeLink(Array('group' => $g, 'text' => $g)) . ', '; | |
86 | } | |
87 | return substr($res,0, -2); | |
88 | ||
89 | case "from": | |
f8391ee4 | 90 | return BananaMessage::formatFrom($text, $this->headers['subject']); |
7027794f | 91 | |
92 | case "references": case "in-reply-to": | |
93 | $rsl = ""; | |
2cd25d86 | 94 | $parents = Banana::$spool->getReferences($this->headers); |
7027794f | 95 | $ndx = 1; |
2cd25d86 | 96 | while (!empty($parents)) { |
97 | $p = array_shift($parents); | |
7027794f | 98 | $rsl .= Banana::$page->makeLink(Array('group' => Banana::$spool->group, |
2cd25d86 | 99 | 'artid' => $p->id, 'text' => $ndx++)) . ' '; |
7027794f | 100 | } |
101 | return $rsl; | |
102 | ||
103 | case "subject": | |
7027794f | 104 | $text = stripslashes($text); |
ba77e884 | 105 | $text = banana_htmlentities($text); |
b87c9103 | 106 | return banana_catchFormats($text); |
7027794f | 107 | |
108 | default: | |
109 | return $text; | |
110 | } | |
111 | } | |
112 | ||
113 | public function getSender() | |
114 | { | |
115 | $from = $this->headers['from']; | |
66e81236 | 116 | $name = trim(strip_tags($from)); |
7027794f | 117 | if (empty($name)) { |
118 | return $from; | |
119 | } | |
120 | return $name; | |
121 | } | |
122 | ||
123 | public function getHeaderValue($hdr) | |
124 | { | |
125 | $hdr = strtolower($hdr); | |
126 | if (!isset($this->headers[$hdr])) { | |
127 | return null; | |
128 | } | |
129 | if ($hdr == 'date') { | |
130 | return strtotime($this->headers['date']); | |
3172a611 | 131 | } else if ($hdr == 'references' || $hdr == 'reply-to') { |
132 | return str_replace('><', '> <', $this->headers[$hdr]); | |
7027794f | 133 | } else { |
134 | return $this->headers[$hdr]; | |
135 | } | |
136 | } | |
137 | ||
138 | public function getHeaders() | |
139 | { | |
e9360b11 | 140 | $this->msg_headers = array_merge($this->msg_headers, Banana::$msgedit_headers, Banana::$profile['headers']); |
7027794f | 141 | $headers = array_map(array($this, 'encodeHeader'), $this->msg_headers); |
142 | return array_merge($headers, parent::getHeaders()); | |
143 | } | |
144 | ||
16800641 | 145 | static public function extractMail($text) |
7027794f | 146 | { |
7027794f | 147 | if (preg_match("/^\"?([^<>\"]+)\"? +<(.+@.+)>$/", $text, $regs)) { |
16800641 | 148 | # From: Mark Horton <mark@cbosgd.ATT.COM> |
7027794f | 149 | $nom = preg_replace("/^'(.*)'$/", '\1', $regs[1]); |
150 | $nom = stripslashes($nom); | |
16800641 FB |
151 | return array($nom, strtolower($regs[2])); |
152 | } else if (preg_match("/^([^ ]+@[^ ]+) \((.*)\)$/", $text, $regs)) { | |
153 | # From: mark@cbosgd.ATT.COM (Mark Horton) | |
154 | return array($regs[2], strtolower($regs[1])); | |
155 | } else if (preg_match("/^<?([^< ]+@[^> ]+)>?$/", $text, $regs)) { | |
156 | # From: <mark@cbosgd.ATT.COM> | |
157 | return array($regs[1], strtolower($regs[1])); | |
158 | } else { | |
159 | # From: mark@cbosgd.ATT.COM | |
160 | return array($text, strtolower($text)); | |
161 | } | |
162 | } | |
163 | ||
164 | static public function formatFrom($text, $subject = '') | |
165 | { | |
166 | list($name, $email) = self::extractMail($text); | |
167 | if ($subject) { | |
168 | $subject = '?subject=' . banana_htmlentities(_b_('Re: ') . $subject, ENT_QUOTES); | |
7027794f | 169 | } |
16800641 FB |
170 | $result = '<a href="mailto:' . $email . $subject . '">' . banana_htmlentities($name) . '</a>'; |
171 | return preg_replace("/\\\(\(|\))/","\\1", $result); | |
7027794f | 172 | } |
173 | ||
e02edbfe | 174 | public function getAuthorName() |
175 | { | |
176 | $text = $this->getHeaderValue('From'); | |
177 | $name = null; | |
178 | if (preg_match("/^([^ ]+@[^ ]+) \((.*)\)$/", $text, $regs)) { | |
179 | $name = $regs[2]; | |
66e81236 | 180 | } |
e02edbfe | 181 | if (preg_match("/^\"?([^<>\"]+)\"? +<(.+@.+)>$/", $text, $regs)) { |
182 | $name = preg_replace("/^'(.*)'$/", '\1', $regs[1]); | |
183 | $name = stripslashes($name); | |
184 | } | |
185 | if ($name) { | |
186 | return preg_replace("/\\\(\(|\))/","\\1", $name); | |
187 | } | |
188 | ||
189 | if (function_exists('hook_getAuthorName') && $name = hook_getAuthorName($this)) { | |
190 | return $name; | |
191 | } | |
192 | ||
193 | if (preg_match("/([^< ]+)@([^> ]+)/", $text, $regs)) { | |
194 | return $regs[1]; | |
195 | } | |
196 | return 'Anonymous'; | |
197 | } | |
198 | ||
7027794f | 199 | static public function formatDate($text) |
200 | { | |
22b95309 | 201 | return strftime("%A %d %B %Y, %H:%M (fuseau serveur)", strtotime($text)); |
7027794f | 202 | } |
203 | ||
204 | public function translateHeaders() | |
205 | { | |
206 | $result = array(); | |
207 | foreach (array_keys($this->headers) as $name) { | |
208 | $value = $this->translateHeaderValue($name); | |
209 | if (!is_null($value)) { | |
210 | $result[$this->translateHeaderName($name)] = $value; | |
211 | } | |
212 | } | |
213 | return $result; | |
214 | } | |
215 | ||
216 | public function getReferences() | |
217 | { | |
218 | $text = $this->headers['references']; | |
219 | $text = str_replace("><","> <", $text); | |
220 | return preg_split('/\s/', $text); | |
221 | } | |
222 | ||
7027794f | 223 | public function hasXFace() |
224 | { | |
52d7843e | 225 | return Banana::$msgshow_xface && |
27934b36 | 226 | ((function_exists('hook_hasxface') && hook_hasXFace($this->headers)) |
227 | || isset($this->headers['x-face'])); | |
7027794f | 228 | } |
229 | ||
230 | public function getXFace() | |
231 | { | |
27934b36 | 232 | if (function_exists('hook_getxface') && hook_getXFace($this->headers)) { |
233 | return; | |
234 | } | |
7027794f | 235 | header('Content-Type: image/gif'); |
236 | $xface = $this->headers['x-face']; | |
237 | passthru('echo ' . escapeshellarg($xface) | |
238 | . '| uncompface -X ' | |
239 | . '| convert -transparent white xbm:- gif:-'); | |
240 | exit; | |
241 | } | |
242 | ||
a9defc17 | 243 | public function getFormattedBody(&$reqtype = null) |
7027794f | 244 | { |
e9360b11 | 245 | $types = Banana::$msgshow_mimeparts; |
a9defc17 | 246 | if (!is_null($reqtype)) { |
247 | array_unshift($types, $reqtype); | |
7027794f | 248 | } |
249 | foreach ($types as $type) { | |
250 | @list($type, $subtype) = explode('/', $type); | |
251 | $parts = $this->getParts($type, $subtype); | |
252 | if (empty($parts)) { | |
253 | continue; | |
254 | } | |
a9defc17 | 255 | $reqtype = implode('/', $parts[0]->getType()); |
3c3a3ce3 | 256 | return $parts[0]->toHtml(); |
7027794f | 257 | } |
258 | return null; | |
259 | } | |
260 | ||
261 | public function quote() | |
262 | { | |
3c3a3ce3 | 263 | foreach (Banana::$msgedit_mimeparts as $type) { |
264 | @list($type, $subtype) = explode('/', $type); | |
265 | $parts = $this->getParts($type, $subtype); | |
266 | if (empty($parts)) { | |
267 | continue; | |
268 | } | |
269 | if ($parts[0] === $this) { | |
270 | return parent::quote(); | |
271 | } | |
272 | return $parts[0]->quote(); | |
7027794f | 273 | } |
3c3a3ce3 | 274 | return null; |
7027794f | 275 | } |
276 | ||
277 | public function canCancel() | |
278 | { | |
279 | if (!Banana::$protocole->canCancel()) { | |
280 | return false; | |
281 | } | |
282 | if (function_exists('hook_checkcancel')) { | |
283 | return hook_checkcancel($this->headers); | |
284 | } | |
1ffc081d | 285 | return Banana::$profile['headers']['From'] == $this->headers['from']; |
7027794f | 286 | } |
287 | ||
288 | public function canSend() | |
289 | { | |
290 | return Banana::$protocole->canSend(); | |
291 | } | |
a3c90095 | 292 | |
293 | public function getSignature() | |
294 | { | |
295 | $email = $this->getHeaderValue('from'); | |
296 | if (preg_match('/<?([^ <]+@[^ >]+)>?/', $email, $matches)) { | |
297 | $email = $matches[1]; | |
298 | } | |
299 | $signature = BananaMimePart::getSignature(); | |
300 | if (empty($signature)) { | |
301 | return $signature; | |
302 | } else { | |
303 | foreach ($signature['identity'] as $ident) { | |
304 | if (strpos($ident, "<$email>") !== false) { | |
305 | return $signature; | |
306 | } | |
307 | } | |
308 | $signature['certified'] = false; | |
309 | $signature['certification_error'] = 'mauvaise identité'; | |
310 | } | |
311 | return $signature; | |
312 | } | |
7027794f | 313 | } |
314 | ||
a90b6fc9 | 315 | // vim:set et sw=4 sts=4 ts=4 fenc=utf-8: |
7027794f | 316 | ?> |