Completed
Pull Request — master (#1276)
by Thomas
05:17
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\AutoConfig\AutoConfig;
35
use OCA\Mail\Service\Logger;
36
use OCA\Mail\Service\UnifiedAccount;
37
use OCP\AppFramework\Controller;
38
use OCP\AppFramework\Db\DoesNotExistException;
39
use OCP\AppFramework\Http\JSONResponse;
40
use OCP\AppFramework\Http\Response;
41
use OCP\AppFramework\Http;
42
use OCP\Files\File;
43
use OCP\IL10N;
44
use OCP\ILogger;
45
use OCP\IRequest;
46
use OCP\Security\ICrypto;
47
48
class AccountsController extends Controller {
49
50
	/** @var AccountService */
51
	private $accountService;
52
53
	/** @var string */
54
	private $currentUserId;
55
56
	/** @var AutoConfig */
57
	private $autoConfig;
58
59
	/** @var \OCP\Files\Folder */
60
	private $userFolder;
61
62
	/** @var ILogger */
63
	private $logger;
64
65
	/** @var IL10N */
66
	private $l10n;
67
68
	/** @var ICrypto */
69
	private $crypto;
70
71
	/**
72
	 * @param string $appName
73
	 * @param IRequest $request
74
	 * @param AccountService $accountService
75
	 * @param $UserId
76
	 * @param $userFolder
77
	 * @param AutoConfig $autoConfig
78
	 * @param Logger $logger
79
	 * @param IL10N $l10n
80
	 * @param ICrypto $crypto
81
	 */
82 15 View Code Duplication
	public function __construct($appName,
0 ignored issues
show
Duplication introduced by
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...
83
		IRequest $request,
84
		AccountService $accountService,
85
		$UserId,
86
		$userFolder,
87
		AutoConfig $autoConfig,
88
		Logger $logger,
89
		IL10N $l10n,
90
		ICrypto $crypto
91
	) {
92 15
		parent::__construct($appName, $request);
93 15
		$this->accountService = $accountService;
94 15
		$this->currentUserId = $UserId;
95 15
		$this->userFolder = $userFolder;
96 15
		$this->autoConfig = $autoConfig;
97 15
		$this->logger = $logger;
98 15
		$this->l10n = $l10n;
99 15
		$this->crypto = $crypto;
100 15
	}
101
102
	/**
103
	 * @NoAdminRequired
104
	 * @NoCSRFRequired
105
	 *
106
	 * @return JSONResponse
107
	 */
108 1
	public function index() {
109 1
		$mailAccounts = $this->accountService->findByUserId($this->currentUserId);
110
111 1
		$json = [];
112 1
		foreach ($mailAccounts as $mailAccount) {
113 1
			$json[] = $mailAccount->getConfiguration();
114 1
		}
115
116 1
		return new JSONResponse($json);
117
	}
118
119
	/**
120
	 * @NoAdminRequired
121
	 *
122
	 * @param int $accountId
123
	 * @return JSONResponse
124
	 */
125 2
	public function show($accountId) {
126
		try {
127 2
			$account = $this->accountService->find($this->currentUserId, $accountId);
128
129 2
			return new JSONResponse($account->getConfiguration());
130 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...
131 1
			return new JSONResponse([], 404);
132
		}
133
	}
134
135
	/**
136
	 * @NoAdminRequired
137
	 */
138
	public function update() {
139
		$response = new Response();
140
		$response->setStatus(Http::STATUS_NOT_IMPLEMENTED);
141
		return $response;
142
	}
143
144
	/**
145
	 * @NoAdminRequired
146
	 *
147
	 * @param int $accountId
148
	 * @return JSONResponse
149
	 */
150 2
	public function destroy($accountId) {
151
		try {
152 2
			$this->accountService->delete($this->currentUserId, $accountId);
153
154 1
			return new JSONResponse();
155 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...
156 1
			return new JSONResponse();
157
		}
158
	}
159
160
	/**
161
	 * @NoAdminRequired
162
	 *
163
	 * @param string $accountName
164
	 * @param string $emailAddress
165
	 * @param string $password
166
	 * @param string $imapHost
167
	 * @param int $imapPort
168
	 * @param string $imapSslMode
169
	 * @param string $imapUser
170
	 * @param string $imapPassword
171
	 * @param string $smtpHost
172
	 * @param int $smtpPort
173
	 * @param string $smtpSslMode
174
	 * @param string $smtpUser
175
	 * @param string $smtpPassword
176
	 * @param bool $autoDetect
177
	 * @return JSONResponse
178
	 */
179 2
	public function create($accountName, $emailAddress, $password,
180
		$imapHost, $imapPort, $imapSslMode, $imapUser, $imapPassword,
181
		$smtpHost, $smtpPort, $smtpSslMode, $smtpUser, $smtpPassword,
182
		$autoDetect) {
183
		try {
184 2
			if ($autoDetect) {
185 2
				$this->logger->info('setting up auto detected account');
186 2
				$newAccount = $this->autoConfig->createAutoDetected($emailAddress, $password, $accountName);
187 2
			} else {
188
				$this->logger->info('Setting up manually configured account');
189
				$newAccount = new MailAccount([
190
					'accountName'  => $accountName,
191
					'emailAddress' => $emailAddress,
192
					'imapHost'     => $imapHost,
193
					'imapPort'     => $imapPort,
194
					'imapSslMode'  => $imapSslMode,
195
					'imapUser'     => $imapUser,
196
					'imapPassword' => $imapPassword,
197
					'smtpHost'     => $smtpHost,
198
					'smtpPort'     => $smtpPort,
199
					'smtpSslMode'  => $smtpSslMode,
200
					'smtpUser'     => $smtpUser,
201
					'smtpPassword' => $smtpPassword
202
				]);
203
				$newAccount->setUserId($this->currentUserId);
204
				$newAccount->setInboundPassword(
205
					$this->crypto->encrypt(
206
						$newAccount->getInboundPassword()
207
					)
208
				);
209
				$newAccount->setOutboundPassword(
210
					$this->crypto->encrypt(
211
						$newAccount->getOutboundPassword()
212
					)
213
				);
214
215
				$a = new Account($newAccount);
216
				$this->logger->debug('Connecting to account {account}', ['account' => $newAccount->getEmail()]);
217
				$a->testConnectivity();
218
			}
219
220 2
			if ($newAccount) {
221 1
				$this->accountService->save($newAccount);
222 1
				$this->logger->debug("account created " . $newAccount->getId());
223 1
				return new JSONResponse(
224 1
					['data' => ['id' => $newAccount->getId()]],
225 1
					Http::STATUS_CREATED);
226
			}
227 1
		} catch (\Exception $ex) {
228
			$this->logger->error('Creating account failed: ' . $ex->getMessage());
229
			return new JSONResponse(
230
				array('message' => $this->l10n->t('Creating account failed: ') . $ex->getMessage()),
231
				HTTP::STATUS_BAD_REQUEST);
232
		}
233
234 1
		$this->logger->info('Auto detect failed');
235 1
		return new JSONResponse(
236 1
			array('message' => $this->l10n->t('Auto detect failed. Please use manual mode.')),
237 1
			HTTP::STATUS_BAD_REQUEST);
238
	}
239
240
	/**
241
	 * @NoAdminRequired
242
	 *
243
	 * @param int $accountId
244
	 * @param string $folderId
245
	 * @param string $subject
246
	 * @param string $body
247
	 * @param string $to
248
	 * @param string $cc
249
	 * @param string $bcc
250
	 * @param int $draftUID
251
	 * @param string $messageId
252
	 * @param mixed $attachments
253
	 * @return JSONResponse
254
	 */
255 4
	public function send($accountId, $folderId, $subject, $body, $to, $cc,
256
		$bcc, $draftUID, $messageId, $attachments) {
257 4
		$account = $this->accountService->find($this->currentUserId, $accountId);
258 4
		if ($account instanceof UnifiedAccount) {
259 2
			list($account, $folderId, $messageId) = $account->resolve($messageId);
260 2
		}
261 4
		if (!$account instanceof Account) {
262
			return new JSONResponse(
263
				['message' => 'Invalid account'],
264
				Http::STATUS_BAD_REQUEST
265
			);
266
		}
267
268 4
		$mailbox = null;
269 4
		if (!is_null($folderId) && !is_null($messageId)) {
270
			// Reply
271 2
			$message = $account->newReplyMessage();
272
273 2
			$mailbox = $account->getMailbox(base64_decode($folderId));
274 2
			$repliedMessage = $mailbox->getMessage($messageId);
275
276 2
			if (is_null($subject)) {
277
				// No subject set – use the original one
278
				$message->setSubject($repliedMessage->getSubject());
279
			} else {
280 2
				$message->setSubject($subject);
281
			}
282
283 2
			if (is_null($to)) {
284
				$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...
285
			} else {
286 2
				$message->setTo(Message::parseAddressList($to));
287
			}
288
289 2
			$message->setRepliedMessage($repliedMessage);
290 2
		} else {
291
			// New message
292 2
			$message = $account->newMessage();
293 2
			$message->setTo(Message::parseAddressList($to));
294 2
			$message->setSubject($subject ? : '');
295
		}
296
297 4
		$message->setFrom($account->getEMailAddress());
298 4
		$message->setCC(Message::parseAddressList($cc));
299 4
		$message->setBcc(Message::parseAddressList($bcc));
300 4
		$message->setContent($body);
301
302 4
		if (is_array($attachments)) {
303 4
			foreach($attachments as $attachment) {
304 4
				$fileName = $attachment['fileName'];
305 4
				if ($this->userFolder->nodeExists($fileName)) {
306 4
					$f = $this->userFolder->get($fileName);
307 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...
308 4
						$message->addAttachmentFromFiles($f);
309 4
					}
310 4
				}
311 4
			}
312 4
		}
313
314
		try {
315 4
			$account->sendMessage($message, $draftUID);
316
317
			// in case of reply we flag the message as answered
318 4
			if ($message instanceof ReplyMessage) {
319 2
				$mailbox->setMessageFlag($messageId, Horde_Imap_Client::FLAG_ANSWERED, true);
320 2
			}
321 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...
322
			$this->logger->error('Sending mail failed: ' . $ex->getMessage());
323
			return new JSONResponse(
324
				array('message' => $ex->getMessage()),
325
				Http::STATUS_INTERNAL_SERVER_ERROR
326
			);
327
		}
328
329 4
		return new JSONResponse();
330
	}
331
332
	/**
333
	 * @NoAdminRequired
334
	 * 
335
	 * @param int $accountId
336
	 * @param string $subject
337
	 * @param string $body
338
	 * @param string $to
339
	 * @param string $cc
340
	 * @param string $bcc
341
	 * @param int $uid
342
	 * @param string $messageId
343
	 * @return JSONResponse
344
	 */
345 4
	public function draft($accountId, $subject, $body, $to, $cc, $bcc, $uid, $messageId) {
346 4
		if (is_null($uid)) {
347 2
			$this->logger->info("Saving a new draft in account <$accountId>");
348 2
		} else {
349 2
			$this->logger->info("Updating draft <$uid> in account <$accountId>");
350
		}
351
352 4
		$account = $this->accountService->find($this->currentUserId, $accountId);
353 4
		if ($account instanceof UnifiedAccount) {
354 2
			list($account) = $account->resolve($messageId);
355 2
		}
356 4
		if (!$account instanceof Account) {
357
			return new JSONResponse(
358
				array('message' => 'Invalid account'),
359
				Http::STATUS_BAD_REQUEST
360
			);
361
		}
362
363 4
		$message = $account->newMessage();
364 4
		$message->setTo(Message::parseAddressList($to));
365 4
		$message->setSubject($subject ? : '');
366 4
		$message->setFrom($account->getEMailAddress());
367 4
		$message->setCC(Message::parseAddressList($cc));
368 4
		$message->setBcc(Message::parseAddressList($bcc));
369 4
		$message->setContent($body);
370
371
		// create transport and save message
372
		try {
373 4
			$newUID = $account->saveDraft($message, $uid);
374 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...
375
			$this->logger->error('Saving draft failed: ' . $ex->getMessage());
376
			return new JSONResponse(
377
				[
378
					'message' => $ex->getMessage()
379
				],
380
				Http::STATUS_INTERNAL_SERVER_ERROR
381
			);
382
		}
383
384 4
		return new JSONResponse([
385
			'uid' => $newUID
386 4
		]);
387
	}
388
389
}
390