Welcome to mirror list, hosted at ThFree Co, Russian Federation.

Connection.php « Wrapped « src « smb « icewind « 3rdparty « files_external « apps - github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 31b72b05d97b2fdc3c855f6c4884f9dd8e4cf76a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<?php
/**
 * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
 * This file is licensed under the Licensed under the MIT license:
 * http://opensource.org/licenses/MIT
 */

namespace Icewind\SMB\Wrapped;

use Icewind\SMB\Exception\AccessDeniedException;
use Icewind\SMB\Exception\AuthenticationException;
use Icewind\SMB\Exception\ConnectException;
use Icewind\SMB\Exception\ConnectionException;
use Icewind\SMB\Exception\ConnectionRefusedException;
use Icewind\SMB\Exception\InvalidHostException;
use Icewind\SMB\Exception\NoLoginServerException;

class Connection extends RawConnection {
	const DELIMITER = 'smb:';
	const DELIMITER_LENGTH = 4;

	/** @var Parser */
	private $parser;

	/**
	 * @param string $command
	 * @param Parser $parser
	 * @param array<string, string> $env
	 */
	public function __construct(string $command, Parser $parser, array $env = []) {
		parent::__construct($command, $env);
		$this->parser = $parser;
	}

	/**
	 * send input to smbclient
	 *
	 * @param string $input
	 */
	public function write(string $input) {
		return parent::write($input . PHP_EOL);
	}

	/**
	 * @throws ConnectException
	 */
	public function clearTillPrompt(): void {
		$this->write('');
		do {
			$promptLine = $this->readLine();
			if ($promptLine === false) {
				break;
			}
			$this->parser->checkConnectionError($promptLine);
		} while (!$this->isPrompt($promptLine));
		if ($this->write('') === false) {
			throw new ConnectionRefusedException();
		}
		$this->readLine();
	}

	/**
	 * get all unprocessed output from smbclient until the next prompt
	 *
	 * @param (callable(string):bool)|null $callback (optional) callback to call for every line read
	 * @return string[]
	 * @throws AuthenticationException
	 * @throws ConnectException
	 * @throws ConnectionException
	 * @throws InvalidHostException
	 * @throws NoLoginServerException
	 * @throws AccessDeniedException
	 */
	public function read(callable $callback = null): array {
		if (!$this->isValid()) {
			throw new ConnectionException('Connection not valid');
		}
		$promptLine = $this->readLine(); //first line is prompt
		if ($promptLine === false) {
			$this->unknownError($promptLine);
		}
		$this->parser->checkConnectionError($promptLine);

		$output = [];
		if (!$this->isPrompt($promptLine)) {
			$line = $promptLine;
		} else {
			$line = $this->readLine();
		}
		if ($line === false) {
			$this->unknownError($promptLine);
		}
		while ($line !== false && !$this->isPrompt($line)) { //next prompt functions as delimiter
			if (is_callable($callback)) {
				$result = $callback($line);
				if ($result === false) { // allow the callback to close the connection for infinite running commands
					$this->close(true);
					break;
				}
			} else {
				$output[] = $line;
			}
			$line = $this->readLine();
		}
		return $output;
	}

	private function isPrompt(string $line): bool {
		return mb_substr($line, 0, self::DELIMITER_LENGTH) === self::DELIMITER;
	}

	/**
	 * @param string|bool $promptLine (optional) prompt line that might contain some info about the error
	 * @throws ConnectException
	 * @return no-return
	 */
	private function unknownError($promptLine = '') {
		if ($promptLine) { //maybe we have some error we missed on the previous line
			throw new ConnectException('Unknown error (' . $promptLine . ')');
		} else {
			$error = $this->readError(); // maybe something on stderr
			if ($error) {
				throw new ConnectException('Unknown error (' . $error . ')');
			} else {
				throw new ConnectException('Unknown error');
			}
		}
	}

	public function close(bool $terminate = true): void {
		if (get_resource_type($this->getInputStream()) === 'stream') {
			// ignore any errors while trying to send the close command, the process might already be dead
			@$this->write('close' . PHP_EOL);
		}
		parent::close($terminate);
	}
}