Issues (78)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

lib/model/imapmessage.php (6 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * @author Alexander Weidinger <[email protected]>
5
 * @author Christoph Wurst <[email protected]>
6
 * @author Christoph Wurst <[email protected]>
7
 * @author Jan-Christoph Borchardt <[email protected]>
8
 * @author Robin McCorkell <[email protected]>
9
 * @author Thomas Mueller <[email protected]>
10
 * @author Thomas Müller <[email protected]>
11
 *
12
 * Mail
13
 *
14
 * This code is free software: you can redistribute it and/or modify
15
 * it under the terms of the GNU Affero General Public License, version 3,
16
 * as published by the Free Software Foundation.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
 * GNU Affero General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License, version 3,
24
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
25
 *
26
 */
27
namespace OCA\Mail\Model;
28
29
use Closure;
30
use Exception;
31
use Horde_Imap_Client;
32
use Horde_Imap_Client_Data_Fetch;
33
use Horde_Mail_Rfc822_List;
34
use OCP\Files\File;
35
use OCA\Mail\Service\Html;
36
use OCP\AppFramework\Db\DoesNotExistException;
37
use OCP\Util;
38
39
class IMAPMessage implements IMessage {
40
41
	use ConvertAddresses;
42
43
	/**
44
	 * @var string[]
45
	 */
46
	private $attachmentsToIgnore = ['signature.asc', 'smime.p7s'];
47
48
	/** @var string */
49
	private $uid;
50
51
	/**
52
	 * @param \Horde_Imap_Client_Socket|null $conn
53
	 * @param \Horde_Imap_Client_Mailbox $mailBox
54
	 * @param integer $messageId
55
	 * @param \Horde_Imap_Client_Data_Fetch|null $fetch
56
	 * @param boolean $loadHtmlMessage
57
	 * @param Html|null $htmlService
58
	 */
59 9
	public function __construct($conn, $mailBox, $messageId, $fetch=null,
60
		$loadHtmlMessage=false, $htmlService = null) {
61 9
		$this->conn = $conn;
62 9
		$this->mailBox = $mailBox;
63 9
		$this->messageId = $messageId;
64 9
		$this->loadHtmlMessage = $loadHtmlMessage;
65
66 9
		$this->htmlService = $htmlService;
0 ignored issues
show
The property htmlService does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
67 9
		if (is_null($htmlService)) {
68 8
			$urlGenerator = \OC::$server->getURLGenerator();
69 8
			$request = \OC::$server->getRequest();
70 8
			$this->htmlService = new Html($urlGenerator, $request);
71 9
		}
72
73 9
		if ($fetch === null) {
74 1
			$this->loadMessageBodies();
75 1
		} else {
76 8
			$this->fetch = $fetch;
77
		}
78 9
	}
79
80
	// output all the following:
81
	public $header = null;
82
	public $htmlMessage = '';
83
	public $plainMessage = '';
84
	public $attachments = [];
85
	private $loadHtmlMessage = false;
86
	private $hasHtmlMessage = false;
87
88
	/**
89
	 * @var \Horde_Imap_Client_Socket
90
	 */
91 7
	private $conn;
92
93
	/**
94
	 * @var \Horde_Imap_Client_Mailbox
95
	 */
96
	private $mailBox;
97
	private $messageId;
98
99
	/**
100
	 * @var \Horde_Imap_Client_Data_Fetch
101
	 */
102
	private $fetch;
103
104
	/**
105
	 * @return int
106
	 */
107 7
	public function getUid() {
108 7
		if (!is_null($this->uid)) {
109
			return $this->uid;
110
		}
111 6
		return $this->fetch->getUid();
112
	}
113
114 7
	public function setUid($uid) {
115
		$this->uid = $uid;
116 7
		$this->attachments = array_map(function($attachment) use ($uid) {
117
			$attachment['messageId'] = $uid;
118 7
			return $attachment;
119
		}, $this->attachments);
120
	}
121
122
	/**
123
	 * @return array
124
	 */
125 7
	public function getFlags() {
126 6
		$flags = $this->fetch->getFlags();
127
		return [
128 7
			'unseen' => !in_array(Horde_Imap_Client::FLAG_SEEN, $flags),
129 6
			'flagged' => in_array(Horde_Imap_Client::FLAG_FLAGGED, $flags),
130 7
			'answered' => in_array(Horde_Imap_Client::FLAG_ANSWERED, $flags),
131 6
			'deleted' => in_array(Horde_Imap_Client::FLAG_DELETED, $flags),
132 7
			'draft' => in_array(Horde_Imap_Client::FLAG_DRAFT, $flags),
133 6
			'forwarded' => in_array(Horde_Imap_Client::FLAG_FORWARDED, $flags),
134 6
			'hasAttachments' => $this->hasAttachments($this->fetch->getStructure())
135 6
		];
136
	}
137
138
	/**
139
	 * @param array $flags
140
	 */
141 7
	public function setFlags(array $flags) {
142
		// TODO: implement
143 7
		throw new Exception('Not implemented');
144
	}
145
146
	/**
147
	 * @return \Horde_Imap_Client_Data_Envelope
148
	 */
149 8
	public function getEnvelope() {
150 8
		return $this->fetch->getEnvelope();
151
	}
152
153
	/**
154
	 * @return string
155
	 */
156 7
	public function getFromEmail() {
157 7
		$e = $this->getEnvelope();
158 7
		$from = $e->from[0];
159 7
		return $from ? $from->bare_address : null;
160
	}
161
162
	/**
163
	 * @return string
164
	 */
165 7
	public function getFrom() {
166 7
		$e = $this->getEnvelope();
167 7
		$from = $e->from[0];
168 7
		return $from ? $from->label : null;
169
	}
170
171
	/**
172
	 * @param string $from
173
	 * @throws Exception
174
	 */
175
	public function setFrom($from) {
176
		throw new Exception('IMAP message is immutable');
177
	}
178
179
	/**
180
	 * @return array
181
	 */
182 6
	public function getFromList() {
183 6
		$e = $this->getEnvelope();
184 6
		return $this->convertAddressList($e->from);
185
	}
186
187
	/**
188
	 * @return string
189
	 */
190 7
	public function getToEmail() {
191 6
		$e = $this->getEnvelope();
192 7
		$to = $e->to[0];
193 6
		return $to ? $to->bare_address : null;
194
	}
195
196 6
	public function getTo() {
197 6
		$e = $this->getEnvelope();
198 6
		$to = $e->to[0];
199 6
		return $to ? $to->label : null;
200
	}
201
202
	/**
203
	 * @param Horde_Mail_Rfc822_List $to
204
	 * @throws Exception
205
	 */
206
	public function setTo(Horde_Mail_Rfc822_List $to) {
207
		throw new Exception('IMAP message is immutable');
208
	}
209
210
	/**
211
	 * @return string
212
	 */
213 6 View Code Duplication
	public function getToList($assoc = false) {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
214 6
		$e = $this->getEnvelope();
215 6
		if ($assoc) {
216 6
			return $this->convertAddressList($e->to);
217
		} else {
218
			return $this->hordeListToStringArray($e->to);
219
		}
220
	}
221
222 6 View Code Duplication
	public function getCCList($assoc = false) {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
223 6
		$e = $this->getEnvelope();
224 6
		if ($assoc) {
225 6
			return $this->convertAddressList($e->cc);
226
		} else {
227
			return $this->hordeListToStringArray($e->cc);
228
		}
229
	}
230
231
	public function setCC(Horde_Mail_Rfc822_List $cc) {
232
		throw new Exception('IMAP message is immutable');
233
	}
234
235 View Code Duplication
	public function getBCCList($assoc = false) {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
236
		$e = $this->getEnvelope();
237
		if ($assoc) {
238
			return $this->convertAddressList($e->bcc);
239
		} else {
240
			return $this->hordeListToStringArray($e->bcc);
241
		}
242
	}
243
244
	public function setBcc(Horde_Mail_Rfc822_List $bcc) {
245
		throw new Exception('IMAP message is immutable');
246
	}
247
248
	public function getReplyToList() {
249
		$e = $this->getEnvelope();
250
		return $this->convertAddressList($e->from);
251
	}
252
253
	public function setReplyTo(array $replyTo) {
0 ignored issues
show
The parameter $replyTo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
254
		throw new Exception('IMAP message is immutable');
255
	}
256
257
	/**
258
	 * on reply, fill cc with everyone from to and cc except yourself
259
	 *
260
	 * @param string $ownMail
261
	 */
262 1
	public function getReplyCcList($ownMail) {
263 1
		$e = $this->getEnvelope();
264 1
		$list = new \Horde_Mail_Rfc822_List();
265 1
		$list->add($e->to);
266 1
		$list->add($e->cc);
267 1
		$list->unique();
268 1
		$list->remove($ownMail);
269 1
		return $this->convertAddressList($list);
270
	}
271
272
	/**
273
	 * Get the ID if available
274
	 *
275
	 * @return int|null
276
	 */
277
	public function getMessageId() {
278
		$e = $this->getEnvelope();
279
		return $e->message_id;
280
	}
281
282
	/**
283
	 * @return string
284
	 */
285 6
	public function getSubject() {
286 6
		$e = $this->getEnvelope();
287 6
		return $e->subject;
288
	}
289
290
	/**
291
	 * @param string $subject
292
	 * @throws Exception
293
	 */
294
	public function setSubject($subject) {
295
		throw new Exception('IMAP message is immutable');
296
	}
297
298
	/**
299
	 * @return \Horde_Imap_Client_DateTime
300
	 */
301 6
	public function getSentDate() {
302 6
		return $this->fetch->getImapDate();
303
	}
304
305 6
	public function getSize() {
306 6
		return $this->fetch->getSize();
307
	}
308
309
	/**
310
	 * @param \Horde_Mime_Part $part
311
	 * @return bool
312
	 */
313 6
	private function hasAttachments($part) {
314 6
		foreach($part->getParts() as $p) {
315
			/**
316
			 * @var \Horde_Mime_Part $p
317
			 */
318
			$filename = $p->getName();
319
320
			if(!is_null($p->getContentId())) {
321
				continue;
322
			}
323
			if(isset($filename)) {
324
				// do not show technical attachments
325
				if(in_array($filename, $this->attachmentsToIgnore)) {
326
					continue;
327
				} else {
328
					return true;
329
				}
330
			}
331
			if($this->hasAttachments($p)) {
332
				return true;
333
			}
334 6
		}
335
336 6
		return false;
337
	}
338
339 1
	private function loadMessageBodies() {
340 1
		$headers = [];
341
342 1
		$fetch_query = new \Horde_Imap_Client_Fetch_Query();
343 1
		$fetch_query->envelope();
344 1
		$fetch_query->structure();
345 1
		$fetch_query->flags();
346 1
		$fetch_query->size();
347 1
		$fetch_query->imapDate();
348
349 1
		$headers = array_merge($headers, [
350 1
			'importance',
351 1
			'list-post',
352
			'x-priority'
353 1
		]);
354 1
		$headers[] = 'content-type';
355
356 1
		$fetch_query->headers('imp', $headers, [
357 1
			'cache' => true,
358
			'peek'  => true
359 1
		]);
360
361
		// $list is an array of Horde_Imap_Client_Data_Fetch objects.
362 1
		$ids = new \Horde_Imap_Client_Ids($this->messageId);
363 1
		$headers = $this->conn->fetch($this->mailBox, $fetch_query, ['ids' => $ids]);
364
		/** @var $fetch \Horde_Imap_Client_Data_Fetch */
365 1
		$fetch = $headers[$this->messageId];
366 1
		if (is_null($fetch)) {
367
			throw new DoesNotExistException("This email ($this->messageId) can't be found. Probably it was deleted from the server recently. Please reload.");
368
		}
369
370
		// set $this->fetch to get to, from ...
371 1
		$this->fetch = $fetch;
372
373
		// analyse the body part
374 1
		$structure = $fetch->getStructure();
375
376
		// debugging below
377 1
		$structure_type = $structure->getPrimaryType();
378 1
		if ($structure_type == 'multipart') {
379 1
			$i = 1;
380 1
			foreach($structure->getParts() as $p) {
381 1
				$this->getPart($p, $i++);
382 1
			}
383 1
		} else {
384
			if ($structure->findBody() != null) {
385
				// get the body from the server
386
				$partId = $structure->findBody();
387
				$this->getPart($structure->getPart($partId), $partId);
388
			}
389
		}
390 1
	}
391
392
	/**
393
	 * @param $p \Horde_Mime_Part
394
	 * @param $partNo
395
	 */
396 1
	private function getPart($p, $partNo) {
397
		// ATTACHMENT
398
		// Any part with a filename is an attachment,
399
		// so an attached text file (type 0) is not mistaken as the message.
400 1
		$filename = $p->getName();
401 1
		if(isset($filename)) {
402
			if(in_array($filename, $this->attachmentsToIgnore)) {
403
				return;
404
			}
405
			$this->attachments[]= [
406
				'id' => $p->getMimeId(),
407
				'messageId' => $this->messageId,
408
				'fileName' => $filename,
409
				'mime' => $p->getType(),
410
				'size' => $p->getBytes(),
411
				'cid' => $p->getContentId()
412
			];
413
			return;
414
		}
415
416 1
		if ($p->getPrimaryType() === 'multipart') {
417
			$this->handleMultiPartMessage($p, $partNo);
418
			return;
419
		}
420
421 1
		if ($p->getType() === 'text/plain') {
422 1
			$this->handleTextMessage($p, $partNo);
423 1
			return;
424
		}
425
426
		// TEXT
427 1
		if ($p->getType() === 'text/calendar') {
428
			// TODO: skip inline ics for now
429
			return;
430
		}
431
432 1
		if ($p->getType() === 'text/html') {
433 1
			$this->handleHtmlMessage($p, $partNo);
434 1
			return;
435
		}
436
437
		// EMBEDDED MESSAGE
438
		// Many bounce notifications embed the original message as type 2,
439
		// but AOL uses type 1 (multipart), which is not handled here.
440
		// There are no PHP functions to parse embedded messages,
441
		// so this just appends the raw source to the main message.
442
		if ($p[0]=='message') {
443
			$data = $this->loadBodyData($p, $partNo);
444
			$this->plainMessage .= trim($data) ."\n\n";
445
		}
446
	}
447
448
	/**
449
	 * @param string $ownMail
450
	 * @param string $specialRole
451
	 */
452
	public function getFullMessage($ownMail, $specialRole=null) {
453
		$mailBody = $this->plainMessage;
454
455
		$data = $this->getListArray();
456
		if ($this->hasHtmlMessage) {
457
			$data['hasHtmlBody'] = true;
458
		} else {
459
			$mailBody = $this->htmlService->convertLinks($mailBody);
460
			list($mailBody, $signature) = $this->htmlService->parseMailBody($mailBody);
461
			$data['body'] = $specialRole === 'drafts' ? $mailBody : nl2br($mailBody);
462
			$data['signature'] = $signature;
463
		}
464
465
		$data['attachments'] = $this->attachments;
466
467
		if ($specialRole === 'sent') {
468
			$data['replyToList'] = $this->getToList(true);
469
			$data['replyCcList'] = $this->getCCList(true);
470
		} else {
471
			$data['replyToList'] = $this->getReplyToList(true);
0 ignored issues
show
The call to IMAPMessage::getReplyToList() has too many arguments starting with true.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
472
			$data['replyCcList'] = $this->getReplyCcList($ownMail);
473
		}
474
		return $data;
475
	}
476
477 6
	public function getListArray() {
478 6
		$data = [];
479 6
		$data['id'] = $this->getUid();
480 6
		$data['from'] = $this->getFrom();
481 6
		$data['fromEmail'] = $this->getFromEmail();
482 6
		$data['fromList'] = $this->getFromList();
483 6
		$data['to'] = $this->getTo();
484 6
		$data['toEmail'] = $this->getToEmail();
485 6
		$data['toList'] = $this->getToList(true);
486 6
		$data['subject'] = $this->getSubject();
487 6
		$data['date'] = Util::formatDate($this->getSentDate()->format('U'));
488 6
		$data['size'] = Util::humanFileSize($this->getSize());
489 6
		$data['flags'] = $this->getFlags();
490 6
		$data['dateInt'] = $this->getSentDate()->getTimestamp();
491 6
		$data['dateIso'] = $this->getSentDate()->format('c');
492 6
		$data['ccList'] = $this->getCCList(true);
493 6
		return $data;
494
	}
495
496
	/**
497
	 * @param int     $accountId
498
	 * @param string  $folderId
499
	 * @param int     $messageId
500
	 * @param Closure $attachments
501
	 * @return string
502
	 */
503 1
	public function getHtmlBody($accountId, $folderId, $messageId, Closure $attachments) {
504 1
		return $this->htmlService->sanitizeHtmlMailBody($this->htmlMessage, [
505 1
			'accountId' => $accountId,
506 1
			'folderId' => $folderId,
507 1
			'messageId' => $messageId,
508 1
		], $attachments);
509
	}
510
511
	/**
512
	 * @return string
513
	 */
514 1
	public function getPlainBody() {
515 1
		return $this->plainMessage;
516
	}
517
518
	/**
519
	 * @param \Horde_Mime_Part $part
520
	 * @param int $partNo
521
	 */
522
	private function handleMultiPartMessage($part, $partNo) {
523
		$i = 1;
524
		foreach ($part->getParts() as $p) {
525
			$this->getPart($p, "$partNo.$i");
526
			$i++;
527
		}
528
	}
529
530
	/**
531
	 * @param \Horde_Mime_Part $p
532
	 * @param int $partNo
533
	 */
534 1
	private function handleTextMessage($p, $partNo) {
535 1
		$data = $this->loadBodyData($p, $partNo);
536 1
		$data = Util::sanitizeHTML($data);
537 1
		$this->plainMessage .= trim($data) ."\n\n";
538 1
	}
539
540
	/**
541
	 * @param \Horde_Mime_Part $p
542
	 * @param int $partNo
543
	 */
544 1
	private function handleHtmlMessage($p, $partNo) {
545 1
		$this->hasHtmlMessage = true;
546 1
		if ($this->loadHtmlMessage) {
547 1
			$data = $this->loadBodyData($p, $partNo);
548 1
			$this->htmlMessage .= $data . "<br><br>";
549 1
		}
550 1
	}
551
552
	/**
553
	 * @param \Horde_Mime_Part $p
554
	 * @param int $partNo
555
	 * @return string
556
	 * @throws DoesNotExistException
557
	 * @throws \Exception
558
	 */
559 1
	private function loadBodyData($p, $partNo) {
560
		// DECODE DATA
561 1
		$fetch_query = new \Horde_Imap_Client_Fetch_Query();
562 1
		$ids = new \Horde_Imap_Client_Ids($this->messageId);
563
564 1
		$fetch_query->bodyPart($partNo, [
565
		    'peek' => true
566 1
		]);
567 1
		$fetch_query->bodyPartSize($partNo);
568 1
		$fetch_query->mimeHeader($partNo, [
569
		    'peek' => true
570 1
		]);
571
572 1
		$headers = $this->conn->fetch($this->mailBox, $fetch_query, ['ids' => $ids]);
573
		/** @var $fetch \Horde_Imap_Client_Data_Fetch */
574 1
		$fetch = $headers[$this->messageId];
575 1
		if (is_null($fetch)) {
576
			throw new DoesNotExistException("Mail body for this mail($this->messageId) could not be loaded");
577
		}
578
579 1
		$mimeHeaders = $fetch->getMimeHeader($partNo, Horde_Imap_Client_Data_Fetch::HEADER_PARSE);
580 1
		if ($enc = $mimeHeaders->getValue('content-transfer-encoding')) {
581
			$p->setTransferEncoding($enc);
582
		}
583
584 1
		$data = $fetch->getBodyPart($partNo);
585
586 1
		$p->setContents($data);
587 1
		$data = $p->getContents();
588
589 1
		$data = iconv($p->getCharset(), 'utf-8//IGNORE', $data);
590 1
		return $data;
591
	}
592
593
	public function getContent() {
594
		return $this->getPlainBody();
595
	}
596
597
	public function setContent($content) {
598
		throw new Exception('IMAP message is immutable');
599
	}
600
601
	/**
602
	 * @return array
603
	 */
604
	public function getAttachments() {
605
		throw new Exception('not implemented');
606
	}
607
608
	/**
609
	 * @param File $file
610
	 */
611
	public function addAttachmentFromFiles(File $file) {
612
		throw new Exception('IMAP message is immutable');
613
	}
614
615
	/**
616
	 * @return IMessage
617
	 */
618
	public function getRepliedMessage() {
619
		throw new Exception('not implemented');
620
	}
621
622
	/**
623
	 * @param IMessage $message
624
	 */
625
	public function setRepliedMessage(IMessage $message) {
626
		throw new Exception('not implemented');
627
	}
628
629
}
630