1: <?php
2: use Symfony\Component\Yaml\Yaml;
3:
4: /**
5: * NUX modules
6: * @package modules
7: * @subpackage nux
8: * @todo filter/disable features depending on imap module sets
9: */
10:
11: if (!defined('DEBUG_MODE')) { die(); }
12:
13: require_once APP_PATH.'modules/nux/functions.php';
14: require_once APP_PATH.'modules/nux/services.php';
15: require_once APP_PATH.'modules/profiles/hm-profiles.php';
16: require_once APP_PATH.'modules/profiles/functions.php';
17:
18: /**
19: * @subpackage nux/handler
20: */
21: class Hm_Handler_nux_dev_news extends Hm_Handler_Module {
22: public function process() {
23: if (!DEBUG_MODE) {
24: return;
25: }
26: $cache = $this->cache->get('nux_dev_news', array());
27: if ($cache) {
28: $this->out('nux_dev_news', $cache);
29: return;
30: }
31: $res = array();
32: $ch = Hm_Functions::c_init();
33: if ($ch) {
34: Hm_Functions::c_setopt($ch, CURLOPT_URL, 'https://api.github.com/repos/cypht-org/cypht/commits');
35: Hm_Functions::c_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
36: Hm_Functions::c_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
37: Hm_Functions::c_setopt($ch, CURLOPT_USERAGENT, $this->request->server["HTTP_USER_AGENT"]);
38: $curl_result = Hm_Functions::c_exec($ch);
39: if (trim($curl_result)) {
40: if (mb_strstr($curl_result, 'API rate limit exceeded')) {
41: return;
42: }
43: $json_commits = json_decode($curl_result);
44: foreach($json_commits as $c) {
45: $msg = trim($c->commit->message);
46: $res[] = array(
47: 'hash' => $c->sha,
48: 'shash' => mb_substr($c->sha, 0, 8),
49: 'name' => $c->commit->author->name,
50: 'age' => date('D, M d', strtotime($c->commit->author->date)),
51: 'note' => (mb_strlen($msg) > 80 ? mb_substr($msg, 0, 80) . "..." : $msg)
52: );
53: }
54: }
55: }
56: $this->cache->set('nux_dev_news', $res);
57: $this->out('nux_dev_news', $res);
58: }
59: }
60:
61: /**
62: * @subpackage nux/handler
63: */
64: class Hm_Handler_nux_homepage_data extends Hm_Handler_Module {
65: public function process() {
66:
67: $imap_servers = NULL;
68: $jmap_servers = NULL;
69: $ews_servers = NULL;
70: $smtp_servers = NULL;
71: $feed_servers = NULL;
72: $profiles = NULL;
73:
74: $modules = $this->config->get_modules();
75:
76: if (data_source_available($modules, 'imap')) {
77: $servers = Hm_IMAP_List::dump(false);
78: $imap_servers = count(array_filter($servers, function($server) { return empty($server['type']) || $server['type'] === 'imap'; }));
79: $jmap_servers = count(array_filter($servers, function($server) { return @$server['type'] === 'jmap'; }));
80: $ews_servers = count(array_filter($servers, function($server) { return @$server['type'] === 'ews'; }));
81: }
82: if (data_source_available($modules, 'feeds')) {
83: $feed_servers = count(Hm_Feed_List::dump(false));
84: }
85: if (data_source_available($modules, 'smtp')) {
86: $servers = Hm_SMTP_List::dump(false);
87: $smtp_servers = count(array_filter($servers, function($server) { return empty($server['type']) || $server['type'] === 'smtp'; }));
88: }
89: if (data_source_available($modules, 'profiles')) {
90: Hm_Profiles::init($this);
91: $profiles = Hm_Profiles::count();
92: }
93:
94: $this->out('nux_server_setup', array(
95: 'imap' => $imap_servers,
96: 'jmap' => $jmap_servers,
97: 'ews' => $ews_servers,
98: 'feeds' => $feed_servers,
99: 'smtp' => $smtp_servers,
100: 'profiles' => $profiles
101: ));
102: $this->out('tzone', $this->user_config->get('timezone_setting'));
103: }
104: }
105: /**
106: * @subpackage nux/handler
107: */
108: class Hm_Handler_process_oauth2_authorization extends Hm_Handler_Module {
109: public function process() {
110: if (array_key_exists('state', $this->request->get) && $this->request->get['state'] == 'nux_authorization') {
111: if (array_key_exists('code', $this->request->get)) {
112: $details = $this->session->get('nux_add_service_details');
113: $oauth2 = new Hm_Oauth2($details['client_id'], $details['client_secret'], $details['redirect_uri']);
114: $result = $oauth2->request_token($details['token_uri'], $this->request->get['code']);
115: if (!empty($result) && array_key_exists('access_token', $result)) {
116: Hm_IMAP_List::add(array(
117: 'name' => $details['name'],
118: 'server' => $details['server'],
119: 'port' => $details['port'],
120: 'tls' => $details['tls'],
121: 'user' => $details['email'],
122: 'pass' => $result['access_token'],
123: 'expiration' => strtotime(sprintf("+%d seconds", $result['expires_in'])),
124: 'refresh_token' => $result['refresh_token'],
125: 'auth' => 'xoauth2',
126: 'type' => $details['type']
127: ));
128: if (isset($details['smtp'])) {
129: Hm_SMTP_List::add(array(
130: 'name' => $details['name'],
131: 'server' => $details['smtp']['server'],
132: 'port' => $details['smtp']['port'],
133: 'tls' => $details['smtp']['tls'],
134: 'auth' => 'xoauth2',
135: 'user' => $details['email'],
136: 'pass' => $result['access_token'],
137: 'expiration' => strtotime(sprintf("+%d seconds", $result['expires_in'])),
138: 'refresh_token' => $result['refresh_token'],
139: 'type' => 'smtp'
140: ));
141: $this->session->record_unsaved('SMTP server added');
142: }
143: Hm_Msgs::add("E-mail account successfully added, To preserve these settings after logout, please go to <a class='alert-link' href='/?page=save'>Save Settings</a>.");
144: Hm_IMAP_List::clean_up();
145: $this->session->del('nux_add_service_details');
146: $this->session->record_unsaved('IMAP server added');
147: $this->session->secure_cookie($this->request, 'hm_reload_folders', '1');
148: $this->session->close_early();
149: }
150: else {
151: Hm_Msgs::add('An Error Occurred', 'danger');
152: }
153: }
154: elseif (array_key_exists('error', $this->request->get)) {
155: Hm_Msgs::add(ucwords(str_replace('_', ' ', $this->request->get['error'])), 'danger');
156: }
157: else {
158: Hm_Msgs::add('An Error Occurred', 'danger');
159: }
160: $this->save_hm_msgs();
161: Hm_Dispatch::page_redirect('?page=servers');
162: }
163: }
164: }
165:
166: /**
167: * @subpackage nux/handler
168: */
169: class Hm_Handler_process_nux_add_service extends Hm_Handler_Module {
170: public function process() {
171: list($success, $form) = $this->process_form(array('nux_pass', 'nux_service', 'nux_email', 'nux_name'));
172: if ($success) {
173: if (Nux_Quick_Services::exists($form['nux_service'])) {
174: $details = Nux_Quick_Services::details($form['nux_service']);
175: $details['name'] = $form['nux_name'];
176: if ($form['nux_service'] == 'all-inkl') {
177: $details['server'] = $this->request->post['nux_all_inkl_login'].$details['server'];
178: $details['smtp']['server'] = $this->request->post['nux_all_inkl_login'].$details['smtp']['server'] ;
179: }
180: $imap_list = array(
181: 'name' => $details['name'],
182: 'server' => $details['server'],
183: 'port' => $details['port'],
184: 'tls' => $details['tls'],
185: 'user' => $form['nux_email'],
186: 'pass' => $form['nux_pass'],
187: 'type' => $details['type']
188: );
189: if ($details['sieve'] && $this->module_is_supported('sievefilters') && $this->user_config->get('enable_sieve_filter_setting', DEFAULT_ENABLE_SIEVE_FILTER)) {
190: $imap_list['sieve_config_host'] = $details['sieve']['host'].':'.$details['sieve']['port'];
191: $imap_list['sieve_tls'] = $details['sieve']['tls'];
192: }
193: $new_id = Hm_IMAP_List::add($imap_list);
194: if (! can_save_last_added_server('Hm_IMAP_List', $form['nux_email'])) {
195: return;
196: }
197: $mailbox = Hm_IMAP_List::connect($new_id, false);
198: if ($mailbox && $mailbox->authed()) {
199: if (isset($details['smtp'])) {
200: Hm_SMTP_List::add(array(
201: 'name' => $details['name'],
202: 'server' => $details['smtp']['server'],
203: 'port' => $details['smtp']['port'],
204: 'tls' => $details['smtp']['tls'],
205: 'user' => $form['nux_email'],
206: 'pass' => $form['nux_pass'],
207: 'type' => 'smtp'
208: ));
209: if (can_save_last_added_server('Hm_SMTP_List', $form['nux_email'])) {
210: $this->session->record_unsaved('SMTP server added');
211: }
212: }
213: Hm_IMAP_List::clean_up();
214: $this->session->record_unsaved('IMAP server added');
215: $this->session->record_unsaved('SMTP server added');
216: $this->session->secure_cookie($this->request, 'hm_reload_folders', '1');
217: Hm_Msgs::add("E-mail account successfully added, To preserve these settings after logout, please go to <a class='alert-link' href='/?page=save'>Save Settings</a>.");
218: $this->session->close_early();
219: $this->out('nux_account_added', true);
220: if ($this->module_is_supported('imap_folders')) {
221: $this->out('nux_server_id', $new_id);
222: $this->out('nux_service_name', $form['nux_service']);
223: }
224: }
225: else {
226: Hm_IMAP_List::del($new_id);
227: Hm_Msgs::add('Authentication failed', 'danger');
228: }
229: }
230: }
231: }
232: }
233:
234: /**
235: * @subpackage nux/handler
236: */
237: class Hm_Handler_setup_nux extends Hm_Handler_Module {
238: public function process() {
239: Nux_Quick_Services::oauth2_setup($this->config);
240: }
241: }
242:
243: /**
244: * @subpackage nux/handler
245: */
246: class Hm_Handler_process_nux_service extends Hm_Handler_Module {
247: public function process() {
248: list($success, $form) = $this->process_form(array('nux_service', 'nux_email'));
249: if ($success) {
250: if (Nux_Quick_Services::exists($form['nux_service'])) {
251: $details = Nux_Quick_Services::details($form['nux_service']);
252: $details['id'] = $form['nux_service'];
253: $details['email'] = $form['nux_email'];
254: if (array_key_exists('nux_account_name', $this->request->post) && trim($this->request->post['nux_account_name'])) {
255: $details['name'] = $this->request->post['nux_account_name'];
256: }
257: $this->out('nux_add_service_details', $details);
258: $this->session->set('nux_add_service_details', $details);
259: }
260: }
261: }
262: }
263:
264: /**
265: * @subpackage nux/handler
266: */
267: class Hm_Handler_get_nux_service_details extends Hm_Handler_Module {
268: public function process() {
269: list($success, $form) = $this->process_form(array('nux_service'));
270: if ($success) {
271: if (Nux_Quick_Services::exists($form['nux_service'])) {
272: $details = Nux_Quick_Services::details($form['nux_service']);
273:
274: $this->out('nux_add_service_details', $details);
275: $this->session->set('nux_add_service_details', $details);
276: }
277: }
278: }
279: }
280:
281: /**
282: * @subpackage nux/handler
283: */
284: class Hm_Handler_process_import_accouts_servers extends Hm_Handler_Module
285: {
286: public function process()
287: {
288: list($success, $form) = $this->process_form(array('accounts_source'));
289:
290: if ($success) {
291: if (! check_file_upload($this->request, 'accounts_sample')) {
292: Hm_Msgs::add('Error while uploading accounts sample', 'danger');
293: return;
294: }
295: try {
296: $extension = pathinfo($this->request->files['accounts_sample']['name'], PATHINFO_EXTENSION);
297: if (in_array(strtolower($extension), ['yaml', 'yml'])) {
298: $servers = Yaml::parseFile($this->request->files['accounts_sample']['tmp_name']);
299: } elseif (in_array($this->request->files['accounts_sample']['type'], ['text/csv', 'text/plain'])) {
300: $servers = [];
301: $server_data = parse_csv_with_headers($this->request->files['accounts_sample']['tmp_name']);
302:
303: // Process keys to have same structure as yaml for single processing below
304: foreach ($server_data as $server_row) {
305: $data = [];
306: $server_name = $server_row['server_name'];
307: unset($server_row['server_name']);
308: foreach ($server_row as $key => $value) {
309: if (strpos($key, '_') !== false) {
310: list($prefix, $suffix) = explode('_', $key, 2);
311: $data[$prefix][$suffix] = $value;
312: } else {
313: $data[$key] = $value;
314: }
315: }
316: $servers[$server_name] = $data;
317: }
318: }
319: } catch (\Exception $e) {
320: Hm_Msgs::add($e->getMessage(), 'danger');
321: return;
322: }
323: if(empty($servers)) {
324: Hm_Msgs::add('Imported file is empty', 'warning');
325: return;
326: }
327: $errors = [];
328: $successes = [];
329: foreach ($servers as $server_name => $server) {
330: $jmap_server_id = $imap_server_id = $smtp_server_id = null;
331: if (! empty($server['jmap']['server'])) {
332: if (! $this->module_is_supported('jmap')) {
333: $errors[] = 'JMAP module is not enabled';
334: } else {
335: $jmap_server_id = connect_to_imap_server(
336: $server['jmap']['server'],
337: $server_name,
338: null,
339: $server['username'],
340: $server['password'],
341: false,
342: null,
343: false,
344: 'jmap',
345: $this,
346: $server['jmap']['hide_from_combined_view'],
347: false,
348: $server['sieve']['tls'],
349: false
350: );
351: if (! $jmap_server_id) {
352: $errors[] = "Failed to save server $server_name: JMAP problem";
353: continue;
354: }
355: }
356: } elseif (! empty($server['imap']['server'])) {
357: if (! $this->module_is_supported('imap')) {
358: $errors[] = 'IMAP module is not enabled';
359: } else {
360: $imap_server_id = connect_to_imap_server(
361: $server['imap']['server'],
362: $server_name,
363: $server['imap']['port'],
364: $server['username'],
365: $server['password'],
366: $server['imap']['tls'],
367: $server['sieve']['host'].':'.($server['sieve']['port'] ?? 4190),
368: ! empty($server['sieve']['host']),
369: 'imap',
370: $this,
371: $server['imap']['hide_from_combined_view'],
372: false,
373: $server['sieve']['tls'],
374: false
375: );
376: if (! $imap_server_id) {
377: $errors[] = "Failed to save server $server_name: IMAP problem";
378: continue;
379: }
380: }
381: }
382: if (! empty($server['smtp']['server'])) {
383: if (!$this->module_is_supported('smtp')) {
384: $errors[] = 'SMTP module is not enabled';
385: } else {
386: $smtp_server_id = connect_to_smtp_server(
387: $server['smtp']['server'],
388: $server_name,
389: $server['smtp']['port'],
390: $server['username'],
391: $server['password'],
392: $server['smtp']['tls'],
393: $server['type'],
394: false
395: );
396: if (! $smtp_server_id) {
397: $errors[] = "Failed to save server $server_name: SMTP problem";
398: if ($jmap_server_id) {
399: Hm_IMAP_List::del($jmap_server_id);
400: } elseif ($imap_server_id) {
401: Hm_IMAP_List::del($imap_server_id);
402: }
403: continue;
404: }
405: }
406: }
407: if(! empty($server['profile']['reply_to']) && ($imap_server_id || $jmap_server_id) && $smtp_server_id) {
408: if (!$this->module_is_supported('profiles')) {
409: $errors[] = 'Profiles module is not enabled';
410: continue;
411: }
412:
413: Hm_Profiles::init($this);
414:
415: add_profile(
416: $server_name,
417: $server['profile']['signature'],
418: $server['profile']['reply_to'],
419: $server['profile']['is_default'],
420: $server['username'],
421: ($server['jmap']['server'] ?? $server['imap']['server']),
422: $server['username'],
423: $smtp_server_id,
424: ($jmap_server_id ?? $imap_server_id),
425: $this
426: );
427: }
428: $successes[] = $server_name;
429: }
430: foreach (array_unique($errors) as $error) {
431: Hm_Msgs::add("$error", 'danger');
432: }
433: foreach ($successes as $success) {
434: Hm_Msgs::add("Server $success imported successfully, To preserve these settings after logout, please go to <a href='/?save'>/?save</a>.");
435: }
436: }
437: }
438: }
439:
440:
441: /**
442: * @subpackage nux/output
443: */
444: class Hm_Output_quick_add_dialog extends Hm_Output_Module {
445: protected function output() {
446: if ($this->get('single_server_mode')) {
447: return '';
448: }
449: return '<div class="quick_add_section">'.
450: '<div class="nux_step_one px-4 pt-">'.
451: '<p class="py-3">'.$this->trans('Quickly add an account from popular E-mail providers. To manually configure an account, use the IMAP/SMTP sections below.').'</p>'.
452: '<div class="row"><div class="col col-lg-4"><div class="form-floating mb-3">'.
453: ' <select id="service_select" name="service_select" class="form-select">'.
454: '<option value="">'.$this->trans('Select an E-mail provider').'</option>'.
455: Nux_Quick_Services::option_list(false, $this).'</select>'.
456: '<label for="service_select">'.$this->trans('Select an E-mail provider').'</label></div>'.
457:
458: '<div class="form-floating mb-3">'.
459: '<input type="email" id="nux_username" class="form-control nux_username" placeholder="'.$this->trans('Your E-mail address').'">'.
460: '<label for="nux_username">'.$this->trans('Username').'</label></div>'.
461:
462: '<div class="form-floating mb-3">'.
463: '<input type="text" id="nux_account_name" class="form-control nux_account_name" placeholder="'.$this->trans('Account Name [optional]').'">'.
464: '<label for="nux_account_name">'.$this->trans('Account name').'</label></div>'.
465:
466: '<input type="button" class="nux_next_button btn btn-primary btn-md px-5" value="'.$this->trans('Next').'">'.
467: '</div></div></div><div class="nux_step_two px-4 pt-3"></div></div>';
468: }
469: }
470:
471: /**
472: * @subpackage nux/output
473: */
474: class Hm_Output_quick_add_multiple_dialog extends Hm_Output_Module {
475: protected function output() {
476: if ($this->get('single_server_mode')) {
477: return '';
478: }
479: $notice = $this->trans('Please ensure your YAML or CSV file follows the correct format');
480: $yaml_file_sample_path = ASSETS_PATH . 'data/server_accounts_sample.yaml';
481: $csv_file_sample_path = ASSETS_PATH . 'data/server_accounts_sample.csv';
482:
483: return '<div class="quick_add_multiple_section">' .
484: '<div class="row"><div class="col col-lg-6"><div class="form-floating mb-3">' .
485: '<form class="quick_add_multiple_server_form" action="?page=servers" method="POST" enctype="multipart/form-data">' .
486: '<p class="mt-2">' . $notice . '</p>' .
487: '<div class="server_form"><br />' .
488: '<div class="row">' .
489: '<div class="col-md-6">' .
490: '<div><a href="' . $yaml_file_sample_path . '" download data-external="true">' . $this->trans('Download a sample yaml file') . '</a></div>' .
491: '</div>' .
492: '<div class="col-md-6">' .
493: '<div><a href="' . $csv_file_sample_path . '" download data-external="true">' . $this->trans('Download a sample csv file') . '</a></div><br />' .
494: '</div>' .
495: '</div>' .
496: '<input type="hidden" name="hm_page_key" value="' . $this->html_safe(Hm_Request_Key::generate()) . '" />' .
497: '<input type="hidden" name="accounts_source" value="yaml" />' .
498: '<label class="screen_reader" for="accounts_sample">' . $this->trans('Yaml or csv File') . '</label>' .
499: '<input class="form-control" id="accounts_sample" type="file" name="accounts_sample" accept=".yaml,.csv"/> <br />' .
500: '<input class="btn btn-primary add_multiple_server_submit" type="submit" name="import_contact" id="import_contact" value="' . $this->trans('Add') . '" /> <input type="reset" class="btn btn-secondary reset_add_multiple_server" value="' .
501: $this->trans('Cancel') . '" /></div></form></div></div></div></div></div>';
502: }
503: }
504:
505: /**
506: * @subpackage nux/output
507: */
508: class Hm_Output_filter_service_select extends Hm_Output_Module {
509: protected function output() {
510: $details = $this->get('nux_add_service_details', array());
511: if (!empty($details)) {
512: if (array_key_exists('auth', $details) && $details['auth'] == 'oauth2') {
513: $this->out('nux_service_step_two', oauth2_form($details, $this));
514: }
515: else {
516: $this->out('nux_service_step_two', credentials_form($details, $this));
517: }
518: }
519: }
520: }
521:
522: /**
523: * @subpackage nux/output
524: */
525: class Hm_Output_service_details extends Hm_Output_Module {
526: protected function output() {
527: $details = $this->get('nux_add_service_details', array());
528: $this->out('service_details', json_encode($details));
529: }
530: }
531:
532: /**
533: * @subpackage nux/output
534: */
535: class Hm_Output_nux_dev_news extends Hm_Output_Module {
536: protected function output() {
537: if (!$this->get('nux_dev_news')) {
538: return '';
539: }
540: $res = '<div class="nux_dev_news mt-3 col-12"><div class="card"><div class="card-body"><div class="card_title"><h4>'.$this->trans('Development Updates').'</h4></div><div class="table-responsive"><table class="table table-bordered">';
541: foreach ($this->get('nux_dev_news', array()) as $vals) {
542: $res .= sprintf('<tr><td><a href="https://github.com/cypht-org/cypht/commit/%s" target="_blank" rel="noopener">%s</a>'.
543: '</td><td class="msg_date">%s</td><td>%s</td><td>%s</td></tr>',
544: $this->html_safe($vals['hash']),
545: $this->html_safe($vals['shash']),
546: $this->html_safe($vals['name']),
547: $this->html_safe($vals['age']),
548: $this->html_safe($vals['note'])
549: );
550: }
551: $res .= '</table></div></div></div></div>';
552: return $res;
553: }
554: }
555:
556: /**
557: * @subpackage nux/output
558: */
559: class Hm_Output_nux_help extends Hm_Output_Module {
560: protected function output() {
561: return '<div class="nux_help mt-3 col-lg-6 col-md-12 col-sm-12"><div class="card"><div class="card-body"><div class="card_title"><h4>'.$this->trans('Help').'</h4></div>'.
562: $this->trans('Cypht is a webmail aggregator client. You can use it to access your E-mail accounts from any server or service that offers any of the main protocols: IMAP/SMTP, Exchange Web Services (EWS) or the newest protocol: JMAP (RFC8621).').' '.
563: '</div></div></div>';
564: }
565: }
566:
567: /**
568: * @subpackage nux/output
569: */
570: class Hm_Output_start_welcome_dialog extends Hm_Output_Module {
571: protected function output() {
572: if ($this->get('single_server_mode')) {
573: return '';
574: }
575: $res = '<div class="nux_welcome mt-3 col-lg-6 col-md-5 col-sm-12"><div class="card"><div class="card-body"><div class="card-title"><h4>'.$this->trans('Welcome to Cypht').'</h4></div>';
576: $res .= '<div class="mb-3"><p>'.$this->trans('Add a popular E-mail source quickly and easily').'</p>';
577: $res .= '<a class="mt-3 btn btn-light" href="?page=servers#quick_add_section"><i class="bi bi-person-plus me-3"></i>'.$this->trans('Add an E-mail Account').'</a>';
578: $res .= '</div>';
579: return $res;
580: }
581: }
582:
583: /**
584: * @subpackage nux/output
585: */
586: class Hm_Output_end_welcome_dialog extends Hm_Output_Module {
587: protected function output() {
588: if ($this->get('single_server_mode')) {
589: return '';
590: }
591: $server_data = $this->get('nux_server_setup', array());
592: $tz = $this->get('tzone');
593: $protos = array('imap', 'jmap', 'ews', 'smtp', 'feeds', 'profiles');
594:
595:
596: $res = '<ul class="mt-4">';
597:
598: foreach ($protos as $proto) {
599: $proto_dsp = $proto;
600: if ($proto == 'feeds') {
601: $proto_dsp = 'RSS/ATOM';
602: }
603: $res .= '<li class="nux_'.$proto.' mt-3">';
604:
605: // Check if user have profiles configured
606: if ($proto == 'profiles') {
607: if ($server_data[$proto] === 0) {
608: $res .= sprintf($this->trans('You don\'t have any profile(s)'));
609: $res .= sprintf(' <a href="?page=profiles">%s</a>', $proto, $this->trans('Add'));
610: }
611: if ($server_data[$proto] > 0) {
612: $res .= sprintf($this->trans('You have %s profile(s)'), $server_data[$proto]);
613: $res .= sprintf(' <a href="?page=profiles">%s</a>', $this->trans('Manage'));
614: }
615: $res .= '</li>';
616: continue;
617: }
618:
619: $section = in_array($proto, ['imap', 'smtp']) ? 'server_config' : $proto;
620: if ($server_data[$proto] === NULL) {
621: $res .= sprintf($this->trans('%s services are not enabled for this site. Sorry about that!'), mb_strtoupper($proto_dsp));
622: }
623: elseif ($server_data[$proto] === 0) {
624: $res .= sprintf($this->trans('You don\'t have any %s sources'), mb_strtoupper($proto_dsp));
625: $res .= sprintf(' <a href="?page=servers#%s_section">%s</a>', $section, $this->trans('Add'));
626: }
627: else {
628: if ($server_data[$proto] > 1) {
629: $res .= sprintf($this->trans('You have %d %s sources'), $server_data[$proto], mb_strtoupper($proto_dsp));
630: }
631: else {
632: $res .= sprintf($this->trans('You have %d %s source'), $server_data[$proto], mb_strtoupper($proto_dsp));
633: }
634: $res .= sprintf(' <a href="?page=servers#%s_section">%s</a>', $section, $this->trans('Manage'));
635: }
636: $res .= '</li>';
637: }
638: $res .= '</ul>';
639: $res .= '<div class="nux_tz">';
640: if (!$tz) {
641: $res .= $this->trans('Your timezone is NOT set');
642: }
643: else {
644: $res .= sprintf($this->trans('Your timezone is set to %s'), $this->html_safe($tz));
645: }
646: $res .= ' <a href="?page=settings#general_setting">'.$this->trans('Update').'</a></div></div></div></div>';
647: return $res;
648: }
649: }
650:
651: /**
652: * @subpackage nux/output
653: */
654: class Hm_Output_nux_message_list_notice extends Hm_Output_Module {
655: protected function output() {
656: $msg = '<div class="nux_empty_combined_view">';
657: $msg .= $this->trans('You don\'t have any data sources assigned to this page.');
658: $msg .= '<br /><a href="?page=servers">'.$this->trans('Add some').'</a>';
659: $msg .= '</div>';
660: return $msg;
661: }
662: }
663:
664: /**
665: * @subpackage nux/output
666: */
667: class Hm_Output_quick_add_section extends Hm_Output_Module {
668: protected function output() {
669: if ($this->get('single_server_mode')) {
670: return '';
671: }
672: return '<div class="nux_add_account"><div data-target=".quick_add_section" class="server_section border-bottom cursor-pointer px-1 py-3 pe-auto"><a href="#" class="pe-auto">'.
673: '<i class="bi bi-check-circle-fill me-3"></i>'.
674: '<b>'.$this->trans('Add an E-mail Account').'</b></a></div>';
675: }
676: }
677: /**
678: * @subpackage nux/output
679: */
680: class Hm_Output_quick_add_multiple_section extends Hm_Output_Module {
681: protected function output() {
682: if ($this->get('single_server_mode')) {
683: return '';
684: }
685: return '<div data-target=".quick_add_multiple_section" class="server_section border-bottom cursor-pointer px-1 py-3 pe-auto"><a href="#" class="pe-auto">' .
686: '<i class="bi bi-filetype-yml me-3"></i>' .
687: '<b>' . $this->trans('Bulk-import accounts using yaml or csv template') . '</b></a></div>';
688: }
689: }
690:
691: /**
692: * @subpackage nux/lib
693: */
694: class Nux_Quick_Services {
695:
696: static private $services = array();
697: static private $oauth2 = array();
698:
699: static public function add($id, $details) {
700: self::$services[$id] = $details;
701: }
702: static public function oauth2_setup($config) {
703: $services = array_keys(config('oauth2'));
704: foreach ($services as $service) {
705: $vals = $config->get($service, []);
706: if (!empty($vals)) {
707: self::$services[$service]['auth'] = 'oauth2';
708: self::$services[$service]['client_id'] = $vals['client_id'];
709: self::$services[$service]['client_secret'] = $vals['client_secret'];
710: self::$services[$service]['redirect_uri'] = $vals['client_uri'];
711: self::$services[$service]['auth_uri'] = $vals['auth_uri'];
712: self::$services[$service]['token_uri'] = $vals['token_uri'];
713: self::$services[$service]['refresh_uri'] = $vals['refresh_uri'];
714: }
715: }
716: self::$oauth2 = config('oauth2');
717: }
718:
719: static public function option_list($current, $mod) {
720: $res = '';
721: uasort(self::$services, function($a, $b) { return strcasecmp($a['name'], $b['name']); });
722: foreach(self::$services as $id => $details) {
723: $res .= '<option value="'.$mod->html_safe($id).'"';
724: if ($id == $current) {
725: $res .= ' selected="selected"';
726: }
727: $res .= '>'.$mod->trans($details['name']);
728: $res .= '</option>';
729: }
730: return $res;
731: }
732:
733: static public function exists($id) {
734: return array_key_exists($id, self::$services);
735: }
736:
737: static public function details($id) {
738: if (array_key_exists($id, self::$services)) {
739: return self::$services[$id];
740: }
741: return array();
742: }
743:
744: static public function get() {
745: return self::$services;
746: }
747: }
748: