1: <?php
2:
3: /**
4: * Server list manager
5: * @package framework
6: * @subpackage servers
7: */
8: trait Hm_Server_Connect {
9:
10: /* list of server connections */
11: protected static $server_list = [];
12:
13: /**
14: * Connect to a server
15: * @param int $id server id
16: * @param mixed $cache cached server data
17: * @param string $user username
18: * @param string $pass password
19: * @param bool $save_credentials true to save the username and password
20: * @return object|false connection object on success, otherwise false
21: */
22: public static function connect($id, $cache = false, $user = false, $pass = false, $save_credentials = false) {
23: if (!array_key_exists($id, self::$server_list)) {
24: return false;
25: }
26: $server = self::$server_list[$id];
27:
28: if ($server['object']) {
29: return $server['object'];
30: }
31: list($user, $pass) = self::user_and_pass($user, $pass, $server);
32: if ($user === false || $pass === false) {
33: return false;
34: }
35:
36: if (self::service_connect($id, $server, $user, $pass, $cache)) {
37: return self::enable_server($id, $user, $pass, $save_credentials);
38: }
39: return self::$server_list[$id]['object'];
40: }
41:
42: /**
43: * Enable server
44: * @param int $id server id
45: * @param string $user username
46: * @param string $pass password
47: * @param bool $save save user and pass
48: */
49: private static function enable_server($id, $user, $pass, $save) {
50: self::$server_list[$id]['connected'] = true;
51: if ($save) {
52: self::$server_list[$id]['user'] = $user;
53: self::$server_list[$id]['pass'] = $pass;
54: }
55: return self::$server_list[$id]['object'];
56: }
57:
58: /**
59: * Process user and pass args
60: * @param string|false $user username
61: * @param string|false $pass password
62: * @param array $server server details
63: * @return array
64: */
65: private static function user_and_pass($user, $pass, $server) {
66: if (array_key_exists('user', $server) && array_key_exists('pass', $server)) {
67: return array($server['user'], $server['pass']);
68: }
69: return array($user, $pass);
70: }
71:
72: /**
73: * Server lists must override this method to connect
74: * @param int $id server id
75: * @param string $server server hostname or ip
76: * @param string $user username for authentication
77: * @param string $pass password for authentication
78: * @param mixed $cache cached connection data
79: * @return bool true on success
80: */
81: public abstract static function service_connect($id, $server, $user, $pass, $cache);
82:
83: /**
84: * Try to disconnect cleanly
85: * @param int $id server id
86: * @return void
87: */
88: public static function clean_up($id = false) {
89: if ($id !== false && array_key_exists($id, self::$server_list)) {
90: self::disconnect($id);
91: } else {
92: foreach (self::$server_list as $index => $server) {
93: self::disconnect($index);
94: }
95: }
96: }
97:
98: /**
99: * Disconnect from a server
100: * @param int $id the server id to disconnect
101: * @return void
102: */
103: public static function disconnect($id) {
104: if (self::$server_list[$id]['connected'] && self::$server_list[$id]['object']) {
105: if (method_exists(self::$server_list[$id]['object'], 'disconnect')) {
106: self::$server_list[$id]['object']->disconnect();
107: }
108: self::$server_list[$id]['connected'] = false;
109: }
110: }
111: }
112:
113: /**
114: * Server list manager
115: * @package framework
116: * @subpackage servers
117: */
118: trait Hm_Server_Modify {
119:
120: use Hm_Server_Connect;
121:
122: /**
123: * Update the oauth2 password and password expiration
124: * @param int $id server id
125: * @param string $pass new password
126: * @param int $expiry new password expiration timestamp
127: * @return bool
128: */
129: public static function update_oauth2_token($id, $pass, $expiry) {
130: if (!array_key_exists($id, self::$server_list)) {
131: return false;
132: }
133: if (!array_key_exists('auth', self::$server_list[$id])) {
134: return false;
135: }
136: if (self::$server_list[$id]['auth'] != 'xoauth2') {
137: return false;
138: }
139: self::$server_list[$id]['pass'] = $pass;
140: self::$server_list[$id]['expiration'] = $expiry;
141: self::$server_list[$id]['object'] = false;
142: return true;
143: }
144:
145: /**
146: * Remove the username and password from a connection
147: * @param int $id server id
148: * @return void
149: */
150: public static function forget_credentials($id) {
151: if (array_key_exists($id, self::$server_list)) {
152: unset(self::$server_list[$id]['user']);
153: unset(self::$server_list[$id]['pass']);
154: }
155: }
156: /**
157: * Toggle the hidden status of a server
158: * @param int $id server id
159: * @param int $hide bool
160: * @return void
161: */
162: public static function toggle_hidden($id, $hide) {
163: if (array_key_exists($id, self::$server_list)) {
164: self::$server_list[$id]['hide'] = $hide;
165: }
166: }
167: }
168:
169: /**
170: * Struct that makes it easy for a module set to manage a list of server connections
171: * @package framework
172: * @subpackage servers
173: */
174: trait Hm_Server_List {
175:
176: use Hm_Server_Modify;
177: use Searchable;
178: use Hm_Repository {
179: Hm_Repository::add as repo_add;
180: Hm_Repository::get as repo_get;
181: }
182:
183: public static function init($name, $user_config, $session) {
184: self::initRepo($name, $user_config, $session, self::$server_list);
185: }
186:
187: /**
188: * Add a server definition
189: * @param array $atts server details
190: * @param int $id server id
191: * @return void
192: */
193: public static function add($atts, $save = true) {
194: $atts['object'] = false;
195: $atts['connected'] = false;
196: return self::repo_add($atts, $save);
197: }
198:
199: /**
200: * Return all server details
201: * @param int $id if not false, return details for this server only
202: * @param bool $full true to return passwords for server connections. CAREFUL!
203: * @return array server details
204: */
205: public static function dump($id = false, $full = false) {
206: $list = [];
207: if ($id !== false) {
208: return self::get($id, $full);
209: }
210: foreach (self::$server_list as $index => $server) {
211: if (!$full) {
212: $server = self::clean($server);
213: }
214: $list[$index] = $server;
215: }
216: return $list;
217: }
218:
219: /**
220: * Get the dataset for the server list
221: * @return array
222: */
223: protected static function getDataset() {
224: return self::$server_list;
225: }
226:
227: /**
228: * @param int $id server id to fetch
229: * @param bool $full true to return passwords for server connections. CAREFUL!
230: * @return array
231: */
232: public static function get($id, $full) {
233: $server = self::repo_get($id);
234: if ($server && ! $full) {
235: return self::clean($server);
236: }
237: return $server;
238: }
239:
240: /*
241: * @param array $server
242: * @return array
243: */
244: public static function clean($server) {
245: if (! array_key_exists('pass', $server) || ! $server['pass']) {
246: $server['nopass'] = true;
247: }
248: unset($server['pass']);
249: return $server;
250: }
251:
252: /**
253: * Fetch a server by the username and servername
254: * @param string $username the user associated with the server
255: * @param string $servername the host associated with the server
256: * @return array|false
257: */
258: public static function fetch($username, $servername) {
259: foreach (self::$server_list as $id => $server) {
260: if (self::match($server, $username, $servername)) {
261: if (array_key_exists('pass', $server)) {
262: unset($server['pass']);
263: }
264: $server['id'] = $id;
265: return $server;
266: }
267: }
268: return false;
269: }
270:
271: /**
272: * @param array $server server details
273: * @param string $user username
274: * @param string $name server name
275: * @return boolean
276: */
277: private static function match($server, $user, $name) {
278: if (array_key_exists('user', $server) && array_key_exists('server', $server)) {
279: if ($user == $server['user'] && $name == $server['server']) {
280: return true;
281: }
282: }
283: return false;
284: }
285:
286: private static function appendPasswordAndUsername(array $server) {
287: $server['password'] = $server['pass'];
288: $server['username'] = $server['user'];
289: return $server;
290: }
291:
292: public static function getForMailbox($id) {
293: $server = self::get($id, true);
294: if ($server) {
295: return self::appendPasswordAndUsername($server);
296: }
297: return false;
298: }
299:
300: public static function dumpForMailbox($id = false) {
301: $list = self::dump($id, true);
302: if ($id !== false) {
303: return self::appendPasswordAndUsername($list);
304: }
305: foreach ($list as $index => $server) {
306: $server = self::appendPasswordAndUsername($server);
307: $list[$index] = $server;
308: }
309: return $list;
310: }
311: }
312: