User color only depends on the email address.
[banana.git] / banana / message.inc.php
CommitLineData
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
10require_once dirname(__FILE__) . '/mimepart.inc.php';
11require_once dirname(__FILE__) . '/message.func.inc.php';
12require_once dirname(__FILE__) . '/banana.inc.php';
13
14final 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
598a1c53 315// vim:set et sw=4 sts=4 ts=4 enc=utf-8:
7027794f 316?>