Fix References compliancy
[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 = "";
94 $parents = preg_grep('/^\d+$/', $this->getTranslatedReferences());
95 $p = array_pop($parents);
96
97 $parents = array();
98 while (!is_null($p)) {
99 array_unshift($parents, $p);
100 $p = Banana::$spool->overview[$p]->parent;
101 }
102 $ndx = 1;
103 foreach ($parents as $p) {
104 $rsl .= Banana::$page->makeLink(Array('group' => Banana::$spool->group,
105 'artid' => $p, 'text' => $ndx++)) . ' ';
106 }
107 return $rsl;
108
109 case "subject":
7027794f 110 $text = stripslashes($text);
ba77e884 111 $text = banana_htmlentities($text);
b87c9103 112 return banana_catchFormats($text);
7027794f 113
114 default:
115 return $text;
116 }
117 }
118
119 public function getSender()
120 {
121 $from = $this->headers['from'];
122 $name = trim(preg_replace('/<[^ ]*>/', '', $from));
123 if (empty($name)) {
124 return $from;
125 }
126 return $name;
127 }
128
129 public function getHeaderValue($hdr)
130 {
131 $hdr = strtolower($hdr);
132 if (!isset($this->headers[$hdr])) {
133 return null;
134 }
135 if ($hdr == 'date') {
136 return strtotime($this->headers['date']);
3172a611 137 } else if ($hdr == 'references' || $hdr == 'reply-to') {
138 return str_replace('><', '> <', $this->headers[$hdr]);
7027794f 139 } else {
140 return $this->headers[$hdr];
141 }
142 }
143
144 public function getHeaders()
145 {
e9360b11 146 $this->msg_headers = array_merge($this->msg_headers, Banana::$msgedit_headers, Banana::$profile['headers']);
7027794f 147 $headers = array_map(array($this, 'encodeHeader'), $this->msg_headers);
148 return array_merge($headers, parent::getHeaders());
149 }
150
f8391ee4 151 static public function formatFrom($text, $subject = '')
7027794f 152 {
153# From: mark@cbosgd.ATT.COM
154# From: <mark@cbosgd.ATT.COM>
155# From: mark@cbosgd.ATT.COM (Mark Horton)
156# From: Mark Horton <mark@cbosgd.ATT.COM>
157 $mailto = '<a href="mailto:';
f8391ee4 158
7027794f 159 $result = banana_htmlentities($text);
f8391ee4 160 if ($subject) {
161 $subject = '?subject=' . banana_htmlentities(_b_('Re: ') . $subject, ENT_QUOTES);
162 }
e02edbfe 163 if (preg_match("/^<?([^< ]+@[^> ]+)>?$/", $text, $regs)) {
f8391ee4 164 $result = $mailto . $regs[1] . $subject . '">' . banana_htmlentities($regs[1]) . '</a>';
7027794f 165 }
166 if (preg_match("/^([^ ]+@[^ ]+) \((.*)\)$/", $text, $regs)) {
f8391ee4 167 $result = $mailto . $regs[1] . $subject . '">' . banana_htmlentities($regs[2]) . '</a>';
7027794f 168 }
169 if (preg_match("/^\"?([^<>\"]+)\"? +<(.+@.+)>$/", $text, $regs)) {
170 $nom = preg_replace("/^'(.*)'$/", '\1', $regs[1]);
171 $nom = stripslashes($nom);
f8391ee4 172 $result = $mailto . $regs[2] . $subject . '">' . banana_htmlentities($nom) . '</a>';
7027794f 173 }
174 return preg_replace("/\\\(\(|\))/","\\1",$result);
175 }
176
e02edbfe 177 public function getAuthorName()
178 {
179 $text = $this->getHeaderValue('From');
180 $name = null;
181 if (preg_match("/^([^ ]+@[^ ]+) \((.*)\)$/", $text, $regs)) {
182 $name = $regs[2];
183 }
184 if (preg_match("/^\"?([^<>\"]+)\"? +<(.+@.+)>$/", $text, $regs)) {
185 $name = preg_replace("/^'(.*)'$/", '\1', $regs[1]);
186 $name = stripslashes($name);
187 }
188 if ($name) {
189 return preg_replace("/\\\(\(|\))/","\\1", $name);
190 }
191
192 if (function_exists('hook_getAuthorName') && $name = hook_getAuthorName($this)) {
193 return $name;
194 }
195
196 if (preg_match("/([^< ]+)@([^> ]+)/", $text, $regs)) {
197 return $regs[1];
198 }
199 return 'Anonymous';
200 }
201
7027794f 202 static public function formatDate($text)
203 {
22b95309 204 return strftime("%A %d %B %Y, %H:%M (fuseau serveur)", strtotime($text));
7027794f 205 }
206
207 public function translateHeaders()
208 {
209 $result = array();
210 foreach (array_keys($this->headers) as $name) {
211 $value = $this->translateHeaderValue($name);
212 if (!is_null($value)) {
213 $result[$this->translateHeaderName($name)] = $value;
214 }
215 }
216 return $result;
217 }
218
219 public function getReferences()
220 {
221 $text = $this->headers['references'];
222 $text = str_replace("><","> <", $text);
223 return preg_split('/\s/', $text);
224 }
225
226 public function getTranslatedReferences()
227 {
228 return BananaMessage::formatReferences($this->headers);
229 }
230
231 static public function formatReferences(array &$refs)
232 {
233 if (isset($refs['references'])) {
345c3a85 234 $text = preg_split('/\s/', str_replace('><', '> <', $refs['references']));
3172a611 235 $references = array();
345c3a85 236 foreach ($text as $id=>&$value) {
237 if (isset(Banana::$spool->ids[$value])) {
3172a611 238 $references[] = Banana::$spool->ids[$value];
345c3a85 239 }
240 }
3172a611 241 return $references;
19fc7e1d 242 } elseif (isset($refs['in-reply-to']) && isset(Banana::$spool->ids[$refs['in-reply-to']])) {
7027794f 243 return array(Banana::$spool->ids[$refs['in-reply-to']]);
244 } else {
245 return array();
246 }
247 }
248
249 public function hasXFace()
250 {
e9360b11 251 return Banana::$msgshow_xface && isset($this->headers['x-face']);
7027794f 252 }
253
254 public function getXFace()
255 {
256 header('Content-Type: image/gif');
257 $xface = $this->headers['x-face'];
258 passthru('echo ' . escapeshellarg($xface)
259 . '| uncompface -X '
260 . '| convert -transparent white xbm:- gif:-');
261 exit;
262 }
263
a9defc17 264 public function getFormattedBody(&$reqtype = null)
7027794f 265 {
e9360b11 266 $types = Banana::$msgshow_mimeparts;
a9defc17 267 if (!is_null($reqtype)) {
268 array_unshift($types, $reqtype);
7027794f 269 }
270 foreach ($types as $type) {
271 @list($type, $subtype) = explode('/', $type);
272 $parts = $this->getParts($type, $subtype);
273 if (empty($parts)) {
274 continue;
275 }
a9defc17 276 $reqtype = implode('/', $parts[0]->getType());
3c3a3ce3 277 return $parts[0]->toHtml();
7027794f 278 }
279 return null;
280 }
281
282 public function quote()
283 {
3c3a3ce3 284 foreach (Banana::$msgedit_mimeparts as $type) {
285 @list($type, $subtype) = explode('/', $type);
286 $parts = $this->getParts($type, $subtype);
287 if (empty($parts)) {
288 continue;
289 }
290 if ($parts[0] === $this) {
291 return parent::quote();
292 }
293 return $parts[0]->quote();
7027794f 294 }
3c3a3ce3 295 return null;
7027794f 296 }
297
298 public function canCancel()
299 {
300 if (!Banana::$protocole->canCancel()) {
301 return false;
302 }
303 if (function_exists('hook_checkcancel')) {
304 return hook_checkcancel($this->headers);
305 }
306 return Banana::$profile['name'] == $this->headers['from'];
307 }
308
309 public function canSend()
310 {
311 return Banana::$protocole->canSend();
312 }
313}
314
598a1c53 315// vim:set et sw=4 sts=4 ts=4 enc=utf-8:
7027794f 316?>