Completed
Pull Request — master (#1276)
by Thomas
04:23
created

AccountsController::autoComplete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 * @author Christoph Wurst <[email protected]>
4
 * @author Christoph Wurst <[email protected]>
5
 * @author Jan-Christoph Borchardt <[email protected]>
6
 * @author Lukas Reschke <[email protected]>
7
 * @author Robin McCorkell <[email protected]>
8
 * @author Thomas Müller <[email protected]>
9
 *
10
 * ownCloud - Mail
11
 *
12
 * This code is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License, version 3,
14
 * as published by the Free Software Foundation.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License, version 3,
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
23
 *
24
 */
25
26
namespace OCA\Mail\Controller;
27
28
use Horde_Imap_Client;
29
use OCA\Mail\Account;
30
use OCA\Mail\Db\MailAccount;
31
use OCA\Mail\Model\Message;
32
use OCA\Mail\Model\ReplyMessage;
33
use OCA\Mail\Service\AccountService;
34
use OCA\Mail\Service\AutoCompletion\AddressCollector;
35
use OCA\Mail\Service\AutoConfig\AutoConfig;
36
use OCA\Mail\Service\Logger;
37
use OCA\Mail\Service\UnifiedAccount;
38
use OCP\AppFramework\Controller;
39
use OCP\AppFramework\Db\DoesNotExistException;
40
use OCP\AppFramework\Http\JSONResponse;
41
use OCP\AppFramework\Http\Response;
42
use OCP\AppFramework\Http;
43
use OCP\Files\File;
44
use OCP\IL10N;
45
use OCP\ILogger;
46
use OCP\IRequest;
47
use OCP\Security\ICrypto;
48
49
class AccountsController extends Controller {
50
51
	/** @var AccountService */
52
	private $accountService;
53
54
	/** @var string */
55
	private $currentUserId;
56
57
	/** @var AutoConfig */
58
	private $autoConfig;
59
60
	/** @var \OCP\Files\Folder */
61
	private $userFolder;
62
63
	/** @var ILogger */
64
	private $logger;
65
66
	/** @var IL10N */
67
	private $l10n;
68
69
	/** @var ICrypto */
70
	private $crypto;
71
72
	/** @var AddressCollector  */
73
	private $addressCollector;
74
75
	/**
76
	 * @param string $appName
77
	 * @param IRequest $request
78
	 * @param AccountService $accountService
79
	 * @param $UserId
80
	 * @param $userFolder
81
	 * @param AutoConfig $autoConfig
82
	 * @param Logger $logger
83
	 * @param IL10N $l10n
84
	 * @param ICrypto $crypto
85
	 */
86 15
	public function __construct($appName,
87
		IRequest $request,
88
		AccountService $accountService,
89
		$UserId,
90
		$userFolder,
91
		AutoConfig $autoConfig,
92
		Logger $logger,
93
		IL10N $l10n,
94
		ICrypto $crypto,
95
		AddressCollector $addressCollector
96
	) {
97 15
		parent::__construct($appName, $request);
98 15
		$this->accountService = $accountService;
99 15
		$this->currentUserId = $UserId;
100 15
		$this->userFolder = $userFolder;
101 15
		$this->autoConfig = $autoConfig;
102 15
		$this->logger = $logger;
103 15
		$this->l10n = $l10n;
104 15
		$this->crypto = $crypto;
105 15
		$this->addressCollector = $addressCollector;
106 15
	}
107
108
	/**
109
	 * @NoAdminRequired
110
	 * @NoCSRFRequired
111
	 *
112
	 * @return JSONResponse
113
	 */
114 1
	public function index() {
115 1
		$mailAccounts = $this->accountService->findByUserId($this->currentUserId);
116
117 1
		$json = [];
118 1
		foreach ($mailAccounts as $mailAccount) {
119 1
			$json[] = $mailAccount->getConfiguration();
120 1
		}
121
122 1
		return new JSONResponse($json);
123
	}
124
125
	/**
126
	 * @NoAdminRequired
127
	 *
128
	 * @param int $accountId
129
	 * @return JSONResponse
130
	 */
131 2
	public function show($accountId) {
132
		try {
133 2
			$account = $this->accountService->find($this->currentUserId, $accountId);
134
135 2
			return new JSONResponse($account->getConfiguration());
136 1
		} catch (DoesNotExistException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\AppFramework\Db\DoesNotExistException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
137 1
			return new JSONResponse([], 404);
138
		}
139
	}
140
141
	/**
142
	 * @NoAdminRequired
143
	 */
144
	public function update() {
145
		$response = new Response();
146
		$response->setStatus(Http::STATUS_NOT_IMPLEMENTED);
147
		return $response;
148
	}
149
150
	/**
151
	 * @NoAdminRequired
152
	 *
153
	 * @param int $accountId
154
	 * @return JSONResponse
155
	 */
156 2
	public function destroy($accountId) {
157
		try {
158 2
			$this->accountService->delete($this->currentUserId, $accountId);
159
160 1
			return new JSONResponse();
161 1
		} catch (DoesNotExistException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\AppFramework\Db\DoesNotExistException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
162 1
			return new JSONResponse();
163
		}
164
	}
165
166
	/**
167
	 * @NoAdminRequired
168
	 *
169
	 * @param string $accountName
170
	 * @param string $emailAddress
171
	 * @param string $password
172
	 * @param string $imapHost
173
	 * @param int $imapPort
174
	 * @param string $imapSslMode
175
	 * @param string $imapUser
176
	 * @param string $imapPassword
177
	 * @param string $smtpHost
178
	 * @param int $smtpPort
179
	 * @param string $smtpSslMode
180
	 * @param string $smtpUser
181
	 * @param string $smtpPassword
182
	 * @param bool $autoDetect
183
	 * @return JSONResponse
184
	 */
185 2
	public function create($accountName, $emailAddress, $password,
186
		$imapHost, $imapPort, $imapSslMode, $imapUser, $imapPassword,
187
		$smtpHost, $smtpPort, $smtpSslMode, $smtpUser, $smtpPassword,
188
		$autoDetect) {
189
		try {
190 2
			if ($autoDetect) {
191 2
				$this->logger->info('setting up auto detected account');
192 2
				$newAccount = $this->autoConfig->createAutoDetected($emailAddress, $password, $accountName);
193 2
			} else {
194
				$this->logger->info('Setting up manually configured account');
195
				$newAccount = new MailAccount([
196
					'accountName'  => $accountName,
197
					'emailAddress' => $emailAddress,
198
					'imapHost'     => $imapHost,
199
					'imapPort'     => $imapPort,
200
					'imapSslMode'  => $imapSslMode,
201
					'imapUser'     => $imapUser,
202
					'imapPassword' => $imapPassword,
203
					'smtpHost'     => $smtpHost,
204
					'smtpPort'     => $smtpPort,
205
					'smtpSslMode'  => $smtpSslMode,
206
					'smtpUser'     => $smtpUser,
207
					'smtpPassword' => $smtpPassword
208
				]);
209
				$newAccount->setUserId($this->currentUserId);
210
				$newAccount->setInboundPassword(
211
					$this->crypto->encrypt(
212
						$newAccount->getInboundPassword()
213
					)
214
				);
215
				$newAccount->setOutboundPassword(
216
					$this->crypto->encrypt(
217
						$newAccount->getOutboundPassword()
218
					)
219
				);
220
221
				$a = new Account($newAccount);
222
				$this->logger->debug('Connecting to account {account}', ['account' => $newAccount->getEmail()]);
223
				$a->testConnectivity();
224
			}
225
226 2
			if ($newAccount) {
227 1
				$this->accountService->save($newAccount);
228 1
				$this->logger->debug("account created " . $newAccount->getId());
229 1
				return new JSONResponse(
230 1
					['data' => ['id' => $newAccount->getId()]],
231 1
					Http::STATUS_CREATED);
232
			}
233 1
		} catch (\Exception $ex) {
234
			$this->logger->error('Creating account failed: ' . $ex->getMessage());
235
			return new JSONResponse(
236
				array('message' => $this->l10n->t('Creating account failed: ') . $ex->getMessage()),
237
				HTTP::STATUS_BAD_REQUEST);
238
		}
239
240 1
		$this->logger->info('Auto detect failed');
241 1
		return new JSONResponse(
242 1
			array('message' => $this->l10n->t('Auto detect failed. Please use manual mode.')),
243 1
			HTTP::STATUS_BAD_REQUEST);
244
	}
245
246
	/**
247
	 * @NoAdminRequired
248
	 *
249
	 * @param int $accountId
250
	 * @param string $folderId
251
	 * @param string $subject
252
	 * @param string $body
253
	 * @param string $to
254
	 * @param string $cc
255
	 * @param string $bcc
256
	 * @param int $draftUID
257
	 * @param string $messageId
258
	 * @param mixed $attachments
259
	 * @return JSONResponse
260
	 */
261 4
	public function send($accountId, $folderId, $subject, $body, $to, $cc,
262
		$bcc, $draftUID, $messageId, $attachments) {
263 4
		$account = $this->accountService->find($this->currentUserId, $accountId);
264 4
		if ($account instanceof UnifiedAccount) {
265 2
			list($account, $folderId, $messageId) = $account->resolve($messageId);
266 2
		}
267 4
		if (!$account instanceof Account) {
268
			return new JSONResponse(
269
				['message' => 'Invalid account'],
270
				Http::STATUS_BAD_REQUEST
271
			);
272
		}
273
274 4
		$mailbox = null;
275 4
		if (!is_null($folderId) && !is_null($messageId)) {
276
			// Reply
277 2
			$message = $account->newReplyMessage();
278
279 2
			$mailbox = $account->getMailbox(base64_decode($folderId));
280 2
			$repliedMessage = $mailbox->getMessage($messageId);
281
282 2
			if (is_null($subject)) {
283
				// No subject set – use the original one
284
				$message->setSubject($repliedMessage->getSubject());
285
			} else {
286 2
				$message->setSubject($subject);
287
			}
288
289 2
			if (is_null($to)) {
290
				$message->setTo(Message::parseAddressList($repliedMessage->getToList()));
0 ignored issues
show
Documentation introduced by
$repliedMessage->getToList() is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
291
			} else {
292 2
				$message->setTo(Message::parseAddressList($to));
293
			}
294
295 2
			$message->setRepliedMessage($repliedMessage);
296 2
		} else {
297
			// New message
298 2
			$message = $account->newMessage();
299 2
			$message->setTo(Message::parseAddressList($to));
300 2
			$message->setSubject($subject ? : '');
301
		}
302
303 4
		$message->setFrom($account->getEMailAddress());
304 4
		$message->setCC(Message::parseAddressList($cc));
305 4
		$message->setBcc(Message::parseAddressList($bcc));
306 4
		$message->setContent($body);
307
308 4
		if (is_array($attachments)) {
309 4
			foreach($attachments as $attachment) {
310 4
				$fileName = $attachment['fileName'];
311 4
				if ($this->userFolder->nodeExists($fileName)) {
312 4
					$f = $this->userFolder->get($fileName);
313 4
					if ($f instanceof File) {
0 ignored issues
show
Bug introduced by
The class OCP\Files\File does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
314 4
						$message->addAttachmentFromFiles($f);
315 4
					}
316 4
				}
317 4
			}
318 4
		}
319
320
		try {
321 4
			$account->sendMessage($message, $draftUID);
322
323
			// in case of reply we flag the message as answered
324 4
			if ($message instanceof ReplyMessage) {
325 2
				$mailbox->setMessageFlag($messageId, Horde_Imap_Client::FLAG_ANSWERED, true);
326 2
			}
327
328
			// Collect mail addresses
329 4
			$addresses = array_merge($message->getToList(), $message->getCCList(), $message->getBCCList());
330 4
			$this->addressCollector->addAddresses($addresses);
331 4
		} catch (\Horde_Exception $ex) {
0 ignored issues
show
Bug introduced by
The class Horde_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
332
			$this->logger->error('Sending mail failed: ' . $ex->getMessage());
333
			return new JSONResponse(
334
				array('message' => $ex->getMessage()),
335
				Http::STATUS_INTERNAL_SERVER_ERROR
336
			);
337
		}
338
339 4
		return new JSONResponse();
340
	}
341
342
	/**
343
	 * @NoAdminRequired
344
	 * 
345
	 * @param int $accountId
346
	 * @param string $subject
347
	 * @param string $body
348
	 * @param string $to
349
	 * @param string $cc
350
	 * @param string $bcc
351
	 * @param int $uid
352
	 * @param string $messageId
353
	 * @return JSONResponse
354
	 */
355 4
	public function draft($accountId, $subject, $body, $to, $cc, $bcc, $uid, $messageId) {
356 4
		if (is_null($uid)) {
357 2
			$this->logger->info("Saving a new draft in account <$accountId>");
358 2
		} else {
359 2
			$this->logger->info("Updating draft <$uid> in account <$accountId>");
360
		}
361
362 4
		$account = $this->accountService->find($this->currentUserId, $accountId);
363 4
		if ($account instanceof UnifiedAccount) {
364 2
			list($account) = $account->resolve($messageId);
365 2
		}
366 4
		if (!$account instanceof Account) {
367
			return new JSONResponse(
368
				array('message' => 'Invalid account'),
369
				Http::STATUS_BAD_REQUEST
370
			);
371
		}
372
373 4
		$message = $account->newMessage();
374 4
		$message->setTo(Message::parseAddressList($to));
375 4
		$message->setSubject($subject ? : '');
376 4
		$message->setFrom($account->getEMailAddress());
377 4
		$message->setCC(Message::parseAddressList($cc));
378 4
		$message->setBcc(Message::parseAddressList($bcc));
379 4
		$message->setContent($body);
380
381
		// create transport and save message
382
		try {
383 4
			$newUID = $account->saveDraft($message, $uid);
384 4
		} catch (\Horde_Exception $ex) {
0 ignored issues
show
Bug introduced by
The class Horde_Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
385
			$this->logger->error('Saving draft failed: ' . $ex->getMessage());
386
			return new JSONResponse(
387
				[
388
					'message' => $ex->getMessage()
389
				],
390
				Http::STATUS_INTERNAL_SERVER_ERROR
391
			);
392
		}
393
394 4
		return new JSONResponse([
395
			'uid' => $newUID
396 4
		]);
397
	}
398
399
}
400