]> git.mxchange.org Git - friendica.git/blob - mod/settings.php
Adapt class structure
[friendica.git] / mod / settings.php
1 <?php
2 /**
3  * @file mod/settings.php
4  */
5
6 use Friendica\App;
7 use Friendica\BaseModule;
8 use Friendica\BaseObject;
9 use Friendica\Content\Feature;
10 use Friendica\Content\Nav;
11 use Friendica\Core\ACL;
12 use Friendica\Core\Config;
13 use Friendica\Core\Hook;
14 use Friendica\Core\L10n;
15 use Friendica\Core\Logger;
16 use Friendica\Core\PConfig;
17 use Friendica\Core\Renderer;
18 use Friendica\Core\Session;
19 use Friendica\Core\System;
20 use Friendica\Core\Theme;
21 use Friendica\Core\Worker;
22 use Friendica\Database\DBA;
23 use Friendica\Model\Contact;
24 use Friendica\Model\GContact;
25 use Friendica\Model\Group;
26 use Friendica\Model\User;
27 use Friendica\Module\Login;
28 use Friendica\Protocol\Email;
29 use Friendica\Util\ACLFormatter;
30 use Friendica\Util\Network;
31 use Friendica\Util\Strings;
32 use Friendica\Util\Temporal;
33 use Friendica\Worker\Delivery;
34
35 function get_theme_config_file($theme)
36 {
37         $theme = Strings::sanitizeFilePathItem($theme);
38
39         $a = \get_app();
40         $base_theme = $a->theme_info['extends'] ?? '';
41
42         if (file_exists("view/theme/$theme/config.php")) {
43                 return "view/theme/$theme/config.php";
44         }
45         if ($base_theme && file_exists("view/theme/$base_theme/config.php")) {
46                 return "view/theme/$base_theme/config.php";
47         }
48         return null;
49 }
50
51 function settings_init(App $a)
52 {
53         if (!local_user()) {
54                 notice(L10n::t('Permission denied.') . EOL);
55                 return;
56         }
57
58         // These lines provide the javascript needed by the acl selector
59
60         $tpl = Renderer::getMarkupTemplate('settings/head.tpl');
61         $a->page['htmlhead'] .= Renderer::replaceMacros($tpl, [
62                 '$ispublic' => L10n::t('everybody')
63         ]);
64
65         $tabs = [
66                 [
67                         'label' => L10n::t('Account'),
68                         'url'   => 'settings',
69                         'selected'      =>  (($a->argc == 1) && ($a->argv[0] === 'settings')?'active':''),
70                         'accesskey' => 'o',
71                 ],
72         ];
73
74         $tabs[] = [
75                 'label' => L10n::t('Two-factor authentication'),
76                 'url' => 'settings/2fa',
77                 'selected' => (($a->argc > 1) && ($a->argv[1] === '2fa') ? 'active' : ''),
78                 'accesskey' => 'o',
79         ];
80
81         $tabs[] =       [
82                 'label' => L10n::t('Profiles'),
83                 'url'   => 'profiles',
84                 'selected'      => (($a->argc == 1) && ($a->argv[0] === 'profiles')?'active':''),
85                 'accesskey' => 'p',
86         ];
87
88         if (Feature::get()) {
89                 $tabs[] =       [
90                                         'label' => L10n::t('Additional features'),
91                                         'url'   => 'settings/features',
92                                         'selected'      => (($a->argc > 1) && ($a->argv[1] === 'features') ? 'active' : ''),
93                                         'accesskey' => 't',
94                                 ];
95         }
96
97         $tabs[] =       [
98                 'label' => L10n::t('Display'),
99                 'url'   => 'settings/display',
100                 'selected'      => (($a->argc > 1) && ($a->argv[1] === 'display')?'active':''),
101                 'accesskey' => 'i',
102         ];
103
104         $tabs[] =       [
105                 'label' => L10n::t('Social Networks'),
106                 'url'   => 'settings/connectors',
107                 'selected'      => (($a->argc > 1) && ($a->argv[1] === 'connectors')?'active':''),
108                 'accesskey' => 'w',
109         ];
110
111         $tabs[] =       [
112                 'label' => L10n::t('Addons'),
113                 'url'   => 'settings/addon',
114                 'selected'      => (($a->argc > 1) && ($a->argv[1] === 'addon')?'active':''),
115                 'accesskey' => 'l',
116         ];
117
118         $tabs[] =       [
119                 'label' => L10n::t('Delegations'),
120                 'url'   => 'settings/delegation',
121                 'selected'      => (($a->argc > 1) && ($a->argv[1] === 'delegation')?'active':''),
122                 'accesskey' => 'd',
123         ];
124
125         $tabs[] =       [
126                 'label' => L10n::t('Connected apps'),
127                 'url' => 'settings/oauth',
128                 'selected' => (($a->argc > 1) && ($a->argv[1] === 'oauth')?'active':''),
129                 'accesskey' => 'b',
130         ];
131
132         $tabs[] =       [
133                 'label' => L10n::t('Export personal data'),
134                 'url' => 'uexport',
135                 'selected' => (($a->argc == 1) && ($a->argv[0] === 'uexport')?'active':''),
136                 'accesskey' => 'e',
137         ];
138
139         $tabs[] =       [
140                 'label' => L10n::t('Remove account'),
141                 'url' => 'removeme',
142                 'selected' => (($a->argc == 1) && ($a->argv[0] === 'removeme')?'active':''),
143                 'accesskey' => 'r',
144         ];
145
146
147         $tabtpl = Renderer::getMarkupTemplate("generic_links_widget.tpl");
148         $a->page['aside'] = Renderer::replaceMacros($tabtpl, [
149                 '$title' => L10n::t('Settings'),
150                 '$class' => 'settings-widget',
151                 '$items' => $tabs,
152         ]);
153
154 }
155
156 function settings_post(App $a)
157 {
158         if (!local_user()) {
159                 return;
160         }
161
162         if (!empty($_SESSION['submanage'])) {
163                 return;
164         }
165
166         if (count($a->user) && !empty($a->user['uid']) && $a->user['uid'] != local_user()) {
167                 notice(L10n::t('Permission denied.') . EOL);
168                 return;
169         }
170
171         $old_page_flags = $a->user['page-flags'];
172
173         if (($a->argc > 1) && ($a->argv[1] === 'oauth') && !empty($_POST['remove'])) {
174                 BaseModule::checkFormSecurityTokenRedirectOnError('/settings/oauth', 'settings_oauth');
175
176                 $key = $_POST['remove'];
177                 DBA::delete('tokens', ['id' => $key, 'uid' => local_user()]);
178                 $a->internalRedirect('settings/oauth/', true);
179                 return;
180         }
181
182         if (($a->argc > 2) && ($a->argv[1] === 'oauth')  && ($a->argv[2] === 'edit'||($a->argv[2] === 'add')) && !empty($_POST['submit'])) {
183                 BaseModule::checkFormSecurityTokenRedirectOnError('/settings/oauth', 'settings_oauth');
184
185                 $name     = $_POST['name']     ?? '';
186                 $key      = $_POST['key']      ?? '';
187                 $secret   = $_POST['secret']   ?? '';
188                 $redirect = $_POST['redirect'] ?? '';
189                 $icon     = $_POST['icon']     ?? '';
190
191                 if ($name == "" || $key == "" || $secret == "") {
192                         notice(L10n::t("Missing some important data!"));
193                 } else {
194                         if ($_POST['submit'] == L10n::t("Update")) {
195                                 q("UPDATE clients SET
196                                                         client_id='%s',
197                                                         pw='%s',
198                                                         name='%s',
199                                                         redirect_uri='%s',
200                                                         icon='%s',
201                                                         uid=%d
202                                                 WHERE client_id='%s'",
203                                         DBA::escape($key),
204                                         DBA::escape($secret),
205                                         DBA::escape($name),
206                                         DBA::escape($redirect),
207                                         DBA::escape($icon),
208                                         local_user(),
209                                         DBA::escape($key)
210                                 );
211                         } else {
212                                 q("INSERT INTO clients
213                                                         (client_id, pw, name, redirect_uri, icon, uid)
214                                                 VALUES ('%s', '%s', '%s', '%s', '%s',%d)",
215                                         DBA::escape($key),
216                                         DBA::escape($secret),
217                                         DBA::escape($name),
218                                         DBA::escape($redirect),
219                                         DBA::escape($icon),
220                                         local_user()
221                                 );
222                         }
223                 }
224                 $a->internalRedirect('settings/oauth/', true);
225                 return;
226         }
227
228         if (($a->argc > 1) && ($a->argv[1] == 'addon')) {
229                 BaseModule::checkFormSecurityTokenRedirectOnError('/settings/addon', 'settings_addon');
230
231                 Hook::callAll('addon_settings_post', $_POST);
232                 return;
233         }
234
235         if (($a->argc > 1) && ($a->argv[1] == 'connectors')) {
236                 BaseModule::checkFormSecurityTokenRedirectOnError('/settings/connectors', 'settings_connectors');
237
238                 if (!empty($_POST['general-submit'])) {
239                         PConfig::set(local_user(), 'system', 'accept_only_sharer', intval($_POST['accept_only_sharer']));
240                         PConfig::set(local_user(), 'system', 'disable_cw', intval($_POST['disable_cw']));
241                         PConfig::set(local_user(), 'system', 'no_intelligent_shortening', intval($_POST['no_intelligent_shortening']));
242                         PConfig::set(local_user(), 'system', 'ostatus_autofriend', intval($_POST['snautofollow']));
243                         PConfig::set(local_user(), 'ostatus', 'default_group', $_POST['group-selection']);
244                         PConfig::set(local_user(), 'ostatus', 'legacy_contact', $_POST['legacy_contact']);
245                 } elseif (!empty($_POST['imap-submit'])) {
246                         $mail_server       =                 $_POST['mail_server']       ?? '';
247                         $mail_port         =                 $_POST['mail_port']         ?? '';
248                         $mail_ssl          = strtolower(trim($_POST['mail_ssl']          ?? ''));
249                         $mail_user         =                 $_POST['mail_user']         ?? '';
250                         $mail_pass         =            trim($_POST['mail_pass']         ?? '');
251                         $mail_action       =            trim($_POST['mail_action']       ?? '');
252                         $mail_movetofolder =            trim($_POST['mail_movetofolder'] ?? '');
253                         $mail_replyto      =                 $_POST['mail_replyto']      ?? '';
254                         $mail_pubmail      =                 $_POST['mail_pubmail']      ?? '';
255
256                         if (
257                                 !Config::get('system', 'dfrn_only')
258                                 && function_exists('imap_open')
259                                 && !Config::get('system', 'imap_disabled')
260                         ) {
261                                 $failed = false;
262                                 $r = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1",
263                                         intval(local_user())
264                                 );
265                                 if (!DBA::isResult($r)) {
266                                         DBA::insert('mailacct', ['uid' => local_user()]);
267                                 }
268                                 if (strlen($mail_pass)) {
269                                         $pass = '';
270                                         openssl_public_encrypt($mail_pass, $pass, $a->user['pubkey']);
271                                         DBA::update('mailacct', ['pass' => bin2hex($pass)], ['uid' => local_user()]);
272                                 }
273                                 $r = q("UPDATE `mailacct` SET `server` = '%s', `port` = %d, `ssltype` = '%s', `user` = '%s',
274                                         `action` = %d, `movetofolder` = '%s',
275                                         `mailbox` = 'INBOX', `reply_to` = '%s', `pubmail` = %d WHERE `uid` = %d",
276                                         DBA::escape($mail_server),
277                                         intval($mail_port),
278                                         DBA::escape($mail_ssl),
279                                         DBA::escape($mail_user),
280                                         intval($mail_action),
281                                         DBA::escape($mail_movetofolder),
282                                         DBA::escape($mail_replyto),
283                                         intval($mail_pubmail),
284                                         intval(local_user())
285                                 );
286                                 Logger::log("mail: updating mailaccount. Response: ".print_r($r, true));
287                                 $r = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1",
288                                         intval(local_user())
289                                 );
290                                 if (DBA::isResult($r)) {
291                                         $eacct = $r[0];
292                                         $mb = Email::constructMailboxName($eacct);
293
294                                         if (strlen($eacct['server'])) {
295                                                 $dcrpass = '';
296                                                 openssl_private_decrypt(hex2bin($eacct['pass']), $dcrpass, $a->user['prvkey']);
297                                                 $mbox = Email::connect($mb, $mail_user, $dcrpass);
298                                                 unset($dcrpass);
299                                                 if (!$mbox) {
300                                                         $failed = true;
301                                                         notice(L10n::t('Failed to connect with email account using the settings provided.') . EOL);
302                                                 }
303                                         }
304                                 }
305                                 if (!$failed) {
306                                         info(L10n::t('Email settings updated.') . EOL);
307                                 }
308                         }
309                 }
310
311                 Hook::callAll('connector_settings_post', $_POST);
312                 return;
313         }
314
315         if (($a->argc > 1) && ($a->argv[1] === 'features')) {
316                 BaseModule::checkFormSecurityTokenRedirectOnError('/settings/features', 'settings_features');
317                 foreach ($_POST as $k => $v) {
318                         if (strpos($k, 'feature_') === 0) {
319                                 PConfig::set(local_user(), 'feature', substr($k, 8), ((intval($v)) ? 1 : 0));
320                         }
321                 }
322                 info(L10n::t('Features updated') . EOL);
323                 return;
324         }
325
326         if (($a->argc > 1) && ($a->argv[1] === 'display')) {
327                 BaseModule::checkFormSecurityTokenRedirectOnError('/settings/display', 'settings_display');
328
329                 $theme             = !empty($_POST['theme'])             ? Strings::escapeTags(trim($_POST['theme']))        : $a->user['theme'];
330                 $mobile_theme      = !empty($_POST['mobile_theme'])      ? Strings::escapeTags(trim($_POST['mobile_theme'])) : '';
331                 $nosmile           = !empty($_POST['nosmile'])           ? intval($_POST['nosmile'])            : 0;
332                 $first_day_of_week = !empty($_POST['first_day_of_week']) ? intval($_POST['first_day_of_week'])  : 0;
333                 $noinfo            = !empty($_POST['noinfo'])            ? intval($_POST['noinfo'])             : 0;
334                 $infinite_scroll   = !empty($_POST['infinite_scroll'])   ? intval($_POST['infinite_scroll'])    : 0;
335                 $no_auto_update    = !empty($_POST['no_auto_update'])    ? intval($_POST['no_auto_update'])     : 0;
336                 $bandwidth_saver   = !empty($_POST['bandwidth_saver'])   ? intval($_POST['bandwidth_saver'])    : 0;
337                 $smart_threading   = !empty($_POST['smart_threading'])   ? intval($_POST['smart_threading'])    : 0;
338                 $nowarn_insecure   = !empty($_POST['nowarn_insecure'])   ? intval($_POST['nowarn_insecure'])    : 0;
339                 $browser_update    = !empty($_POST['browser_update'])    ? intval($_POST['browser_update'])     : 0;
340                 if ($browser_update != -1) {
341                         $browser_update = $browser_update * 1000;
342                         if ($browser_update < 10000) {
343                                 $browser_update = 10000;
344                         }
345                 }
346
347                 $itemspage_network = !empty($_POST['itemspage_network'])  ? intval($_POST['itemspage_network'])  : 40;
348                 if ($itemspage_network > 100) {
349                         $itemspage_network = 100;
350                 }
351                 $itemspage_mobile_network = !empty($_POST['itemspage_mobile_network']) ? intval($_POST['itemspage_mobile_network']) : 20;
352                 if ($itemspage_mobile_network > 100) {
353                         $itemspage_mobile_network = 100;
354                 }
355
356                 if ($mobile_theme !== '') {
357                         PConfig::set(local_user(), 'system', 'mobile_theme', $mobile_theme);
358                 }
359
360                 PConfig::set(local_user(), 'system', 'nowarn_insecure'         , $nowarn_insecure);
361                 PConfig::set(local_user(), 'system', 'update_interval'         , $browser_update);
362                 PConfig::set(local_user(), 'system', 'itemspage_network'       , $itemspage_network);
363                 PConfig::set(local_user(), 'system', 'itemspage_mobile_network', $itemspage_mobile_network);
364                 PConfig::set(local_user(), 'system', 'no_smilies'              , $nosmile);
365                 PConfig::set(local_user(), 'system', 'first_day_of_week'       , $first_day_of_week);
366                 PConfig::set(local_user(), 'system', 'ignore_info'             , $noinfo);
367                 PConfig::set(local_user(), 'system', 'infinite_scroll'         , $infinite_scroll);
368                 PConfig::set(local_user(), 'system', 'no_auto_update'          , $no_auto_update);
369                 PConfig::set(local_user(), 'system', 'bandwidth_saver'         , $bandwidth_saver);
370                 PConfig::set(local_user(), 'system', 'smart_threading'         , $smart_threading);
371
372                 if (in_array($theme, Theme::getAllowedList())) {
373                         if ($theme == $a->user['theme']) {
374                                 // call theme_post only if theme has not been changed
375                                 if (($themeconfigfile = get_theme_config_file($theme)) !== null) {
376                                         require_once $themeconfigfile;
377                                         theme_post($a);
378                                 }
379                         } else {
380                                 DBA::update('user', ['theme' => $theme], ['uid' => local_user()]);
381                         }
382                 } else {
383                         notice(L10n::t('The theme you chose isn\'t available.'));
384                 }
385
386                 Hook::callAll('display_settings_post', $_POST);
387                 $a->internalRedirect('settings/display');
388                 return; // NOTREACHED
389         }
390
391         BaseModule::checkFormSecurityTokenRedirectOnError('/settings', 'settings');
392
393         if (!empty($_POST['resend_relocate'])) {
394                 Worker::add(PRIORITY_HIGH, 'Notifier', Delivery::RELOCATION, local_user());
395                 info(L10n::t("Relocate message has been send to your contacts"));
396                 $a->internalRedirect('settings');
397         }
398
399         Hook::callAll('settings_post', $_POST);
400
401         if (!empty($_POST['password']) || !empty($_POST['confirm'])) {
402                 $newpass = $_POST['password'];
403                 $confirm = $_POST['confirm'];
404
405                 try {
406                         if ($newpass != $confirm) {
407                                 throw new Exception(L10n::t('Passwords do not match.'));
408                         }
409
410                         //  check if the old password was supplied correctly before changing it to the new value
411                         User::getIdFromPasswordAuthentication(local_user(), $_POST['opassword']);
412
413                         $result = User::updatePassword(local_user(), $newpass);
414                         if (!DBA::isResult($result)) {
415                                 throw new Exception(L10n::t('Password update failed. Please try again.'));
416                         }
417
418                         info(L10n::t('Password changed.'));
419                 } catch (Exception $e) {
420                         notice($e->getMessage());
421                         notice(L10n::t('Password unchanged.'));
422                 }
423         }
424
425         $username         = (!empty($_POST['username'])   ? Strings::escapeTags(trim($_POST['username']))     : '');
426         $email            = (!empty($_POST['email'])      ? Strings::escapeTags(trim($_POST['email']))        : '');
427         $timezone         = (!empty($_POST['timezone'])   ? Strings::escapeTags(trim($_POST['timezone']))     : '');
428         $language         = (!empty($_POST['language'])   ? Strings::escapeTags(trim($_POST['language']))     : '');
429
430         $defloc           = (!empty($_POST['defloc'])     ? Strings::escapeTags(trim($_POST['defloc']))       : '');
431         $openid           = (!empty($_POST['openid_url']) ? Strings::escapeTags(trim($_POST['openid_url']))   : '');
432         $maxreq           = (!empty($_POST['maxreq'])     ? intval($_POST['maxreq'])             : 0);
433         $expire           = (!empty($_POST['expire'])     ? intval($_POST['expire'])             : 0);
434         $def_gid          = (!empty($_POST['group-selection']) ? intval($_POST['group-selection']) : 0);
435
436
437         $expire_items     = (!empty($_POST['expire_items']) ? intval($_POST['expire_items'])     : 0);
438         $expire_notes     = (!empty($_POST['expire_notes']) ? intval($_POST['expire_notes'])     : 0);
439         $expire_starred   = (!empty($_POST['expire_starred']) ? intval($_POST['expire_starred']) : 0);
440         $expire_photos    = (!empty($_POST['expire_photos'])? intval($_POST['expire_photos'])    : 0);
441         $expire_network_only    = (!empty($_POST['expire_network_only'])? intval($_POST['expire_network_only'])  : 0);
442
443         $allow_location   = ((!empty($_POST['allow_location']) && (intval($_POST['allow_location']) == 1)) ? 1: 0);
444         $publish          = ((!empty($_POST['profile_in_directory']) && (intval($_POST['profile_in_directory']) == 1)) ? 1: 0);
445         $net_publish      = ((!empty($_POST['profile_in_netdirectory']) && (intval($_POST['profile_in_netdirectory']) == 1)) ? 1: 0);
446         $old_visibility   = ((!empty($_POST['visibility']) && (intval($_POST['visibility']) == 1)) ? 1 : 0);
447         $account_type     = ((!empty($_POST['account-type']) && (intval($_POST['account-type']))) ? intval($_POST['account-type']) : 0);
448         $page_flags       = ((!empty($_POST['page-flags']) && (intval($_POST['page-flags']))) ? intval($_POST['page-flags']) : 0);
449         $blockwall        = ((!empty($_POST['blockwall']) && (intval($_POST['blockwall']) == 1)) ? 0: 1); // this setting is inverted!
450         $blocktags        = ((!empty($_POST['blocktags']) && (intval($_POST['blocktags']) == 1)) ? 0: 1); // this setting is inverted!
451         $unkmail          = ((!empty($_POST['unkmail']) && (intval($_POST['unkmail']) == 1)) ? 1: 0);
452         $cntunkmail       = (!empty($_POST['cntunkmail']) ? intval($_POST['cntunkmail']) : 0);
453         $suggestme        = (!empty($_POST['suggestme']) ? intval($_POST['suggestme'])  : 0);
454         $hide_friends     = (($_POST['hide-friends'] == 1) ? 1: 0);
455         $hidewall         = (($_POST['hidewall'] == 1) ? 1: 0);
456
457         $email_textonly   = (($_POST['email_textonly'] == 1) ? 1 : 0);
458         $detailed_notif   = (($_POST['detailed_notif'] == 1) ? 1 : 0);
459
460         $notify = 0;
461
462         if (!empty($_POST['notify1'])) {
463                 $notify += intval($_POST['notify1']);
464         }
465         if (!empty($_POST['notify2'])) {
466                 $notify += intval($_POST['notify2']);
467         }
468         if (!empty($_POST['notify3'])) {
469                 $notify += intval($_POST['notify3']);
470         }
471         if (!empty($_POST['notify4'])) {
472                 $notify += intval($_POST['notify4']);
473         }
474         if (!empty($_POST['notify5'])) {
475                 $notify += intval($_POST['notify5']);
476         }
477         if (!empty($_POST['notify6'])) {
478                 $notify += intval($_POST['notify6']);
479         }
480         if (!empty($_POST['notify7'])) {
481                 $notify += intval($_POST['notify7']);
482         }
483         if (!empty($_POST['notify8'])) {
484                 $notify += intval($_POST['notify8']);
485         }
486
487         // Adjust the page flag if the account type doesn't fit to the page flag.
488         if (($account_type == User::ACCOUNT_TYPE_PERSON) && !in_array($page_flags, [User::PAGE_FLAGS_NORMAL, User::PAGE_FLAGS_SOAPBOX, User::PAGE_FLAGS_FREELOVE])) {
489                 $page_flags = User::PAGE_FLAGS_NORMAL;
490         } elseif (($account_type == User::ACCOUNT_TYPE_ORGANISATION) && !in_array($page_flags, [User::PAGE_FLAGS_SOAPBOX])) {
491                 $page_flags = User::PAGE_FLAGS_SOAPBOX;
492         } elseif (($account_type == User::ACCOUNT_TYPE_NEWS) && !in_array($page_flags, [User::PAGE_FLAGS_SOAPBOX])) {
493                 $page_flags = User::PAGE_FLAGS_SOAPBOX;
494         } elseif (($account_type == User::ACCOUNT_TYPE_COMMUNITY) && !in_array($page_flags, [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP])) {
495                 $page_flags = User::PAGE_FLAGS_COMMUNITY;
496         }
497
498         $err = '';
499
500         if ($username != $a->user['username']) {
501                 if (strlen($username) > 40) {
502                         $err .= L10n::t(' Please use a shorter name.');
503                 }
504                 if (strlen($username) < 3) {
505                         $err .= L10n::t(' Name too short.');
506                 }
507         }
508
509         if ($email != $a->user['email']) {
510                 //  check for the correct password
511                 if (!User::authenticate(intval(local_user()), $_POST['mpassword'])) {
512                         $err .= L10n::t('Wrong Password') . EOL;
513                         $email = $a->user['email'];
514                 }
515                 //  check the email is valid
516                 if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
517                         $err .= L10n::t('Invalid email.');
518                 }
519                 //  ensure new email is not the admin mail
520                 if (Config::get('config', 'admin_email')) {
521                         $adminlist = explode(",", str_replace(" ", "", strtolower(Config::get('config', 'admin_email'))));
522                         if (in_array(strtolower($email), $adminlist)) {
523                                 $err .= L10n::t('Cannot change to that email.');
524                                 $email = $a->user['email'];
525                         }
526                 }
527         }
528
529         if (strlen($err)) {
530                 notice($err . EOL);
531                 return;
532         }
533
534         if (($timezone != $a->user['timezone']) && strlen($timezone)) {
535                 date_default_timezone_set($timezone);
536         }
537
538         /** @var ACLFormatter $aclFormatter */
539         $aclFormatter = BaseObject::getClass(ACLFormatter::class);
540
541         $str_group_allow   = !empty($_POST['group_allow'])   ? $aclFormatter->toString($_POST['group_allow'])   : '';
542         $str_contact_allow = !empty($_POST['contact_allow']) ? $aclFormatter->toString($_POST['contact_allow']) : '';
543         $str_group_deny    = !empty($_POST['group_deny'])    ? $aclFormatter->toString($_POST['group_deny'])    : '';
544         $str_contact_deny  = !empty($_POST['contact_deny'])  ? $aclFormatter->toString($_POST['contact_deny'])  : '';
545
546         $openidserver = $a->user['openidserver'];
547         //$openid = Strings::normaliseOpenID($openid);
548
549         // If openid has changed or if there's an openid but no openidserver, try and discover it.
550         if ($openid != $a->user['openid'] || (strlen($openid) && (!strlen($openidserver)))) {
551                 if (Network::isUrlValid($openid)) {
552                         Logger::log('updating openidserver');
553                         $open_id_obj = new LightOpenID($a->getHostName());
554                         $open_id_obj->identity = $openid;
555                         $openidserver = $open_id_obj->discover($open_id_obj->identity);
556                 } else {
557                         $openidserver = '';
558                 }
559         }
560
561         PConfig::set(local_user(), 'expire', 'items', $expire_items);
562         PConfig::set(local_user(), 'expire', 'notes', $expire_notes);
563         PConfig::set(local_user(), 'expire', 'starred', $expire_starred);
564         PConfig::set(local_user(), 'expire', 'photos', $expire_photos);
565         PConfig::set(local_user(), 'expire', 'network_only', $expire_network_only);
566
567         PConfig::set(local_user(), 'system', 'suggestme', $suggestme);
568
569         PConfig::set(local_user(), 'system', 'email_textonly', $email_textonly);
570         PConfig::set(local_user(), 'system', 'detailed_notif', $detailed_notif);
571
572         if ($page_flags == User::PAGE_FLAGS_PRVGROUP) {
573                 $hidewall = 1;
574                 if (!$str_contact_allow && !$str_group_allow && !$str_contact_deny && !$str_group_deny) {
575                         if ($def_gid) {
576                                 info(L10n::t('Private forum has no privacy permissions. Using default privacy group.'). EOL);
577                                 $str_group_allow = '<' . $def_gid . '>';
578                         } else {
579                                 notice(L10n::t('Private forum has no privacy permissions and no default privacy group.') . EOL);
580                         }
581                 }
582         }
583
584
585         $r = q("UPDATE `user` SET `username` = '%s', `email` = '%s',
586                                 `openid` = '%s', `timezone` = '%s',
587                                 `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s',
588                                 `notify-flags` = %d, `page-flags` = %d, `account-type` = %d, `default-location` = '%s',
589                                 `allow_location` = %d, `maxreq` = %d, `expire` = %d, `openidserver` = '%s',
590                                 `def_gid` = %d, `blockwall` = %d, `hidewall` = %d, `blocktags` = %d,
591                                 `unkmail` = %d, `cntunkmail` = %d, `language` = '%s'
592                         WHERE `uid` = %d",
593                         DBA::escape($username),
594                         DBA::escape($email),
595                         DBA::escape($openid),
596                         DBA::escape($timezone),
597                         DBA::escape($str_contact_allow),
598                         DBA::escape($str_group_allow),
599                         DBA::escape($str_contact_deny),
600                         DBA::escape($str_group_deny),
601                         intval($notify),
602                         intval($page_flags),
603                         intval($account_type),
604                         DBA::escape($defloc),
605                         intval($allow_location),
606                         intval($maxreq),
607                         intval($expire),
608                         DBA::escape($openidserver),
609                         intval($def_gid),
610                         intval($blockwall),
611                         intval($hidewall),
612                         intval($blocktags),
613                         intval($unkmail),
614                         intval($cntunkmail),
615                         DBA::escape($language),
616                         intval(local_user())
617         );
618         if (DBA::isResult($r)) {
619                 info(L10n::t('Settings updated.') . EOL);
620         }
621
622         // clear session language
623         unset($_SESSION['language']);
624
625         q("UPDATE `profile`
626                 SET `publish` = %d,
627                 `name` = '%s',
628                 `net-publish` = %d,
629                 `hide-friends` = %d
630                 WHERE `is-default` = 1 AND `uid` = %d",
631                 intval($publish),
632                 DBA::escape($username),
633                 intval($net_publish),
634                 intval($hide_friends),
635                 intval(local_user())
636         );
637
638         Contact::updateSelfFromUserID(local_user());
639
640         if (($old_visibility != $net_publish) || ($page_flags != $old_page_flags)) {
641                 // Update global directory in background
642                 $url = $_SESSION['my_url'];
643                 if ($url && strlen(Config::get('system', 'directory'))) {
644                         Worker::add(PRIORITY_LOW, "Directory", $url);
645                 }
646         }
647
648         Worker::add(PRIORITY_LOW, 'ProfileUpdate', local_user());
649
650         // Update the global contact for the user
651         GContact::updateForUser(local_user());
652
653         $a->internalRedirect('settings');
654         return; // NOTREACHED
655 }
656
657
658 function settings_content(App $a)
659 {
660         $o = '';
661         Nav::setSelected('settings');
662
663         if (!local_user()) {
664                 //notice(L10n::t('Permission denied.') . EOL);
665                 return Login::form();
666         }
667
668         if (!empty($_SESSION['submanage'])) {
669                 notice(L10n::t('Permission denied.') . EOL);
670                 return;
671         }
672
673         if (($a->argc > 1) && ($a->argv[1] === 'oauth')) {
674                 if (($a->argc > 2) && ($a->argv[2] === 'add')) {
675                         $tpl = Renderer::getMarkupTemplate('settings/oauth_edit.tpl');
676                         $o .= Renderer::replaceMacros($tpl, [
677                                 '$form_security_token' => BaseModule::getFormSecurityToken("settings_oauth"),
678                                 '$title'        => L10n::t('Add application'),
679                                 '$submit'       => L10n::t('Save Settings'),
680                                 '$cancel'       => L10n::t('Cancel'),
681                                 '$name'         => ['name', L10n::t('Name'), '', ''],
682                                 '$key'          => ['key', L10n::t('Consumer Key'), '', ''],
683                                 '$secret'       => ['secret', L10n::t('Consumer Secret'), '', ''],
684                                 '$redirect'     => ['redirect', L10n::t('Redirect'), '', ''],
685                                 '$icon'         => ['icon', L10n::t('Icon url'), '', ''],
686                         ]);
687                         return $o;
688                 }
689
690                 if (($a->argc > 3) && ($a->argv[2] === 'edit')) {
691                         $r = q("SELECT * FROM clients WHERE client_id='%s' AND uid=%d",
692                                         DBA::escape($a->argv[3]),
693                                         local_user());
694
695                         if (!DBA::isResult($r)) {
696                                 notice(L10n::t("You can't edit this application."));
697                                 return;
698                         }
699                         $app = $r[0];
700
701                         $tpl = Renderer::getMarkupTemplate('settings/oauth_edit.tpl');
702                         $o .= Renderer::replaceMacros($tpl, [
703                                 '$form_security_token' => BaseModule::getFormSecurityToken("settings_oauth"),
704                                 '$title'        => L10n::t('Add application'),
705                                 '$submit'       => L10n::t('Update'),
706                                 '$cancel'       => L10n::t('Cancel'),
707                                 '$name'         => ['name', L10n::t('Name'), $app['name'] , ''],
708                                 '$key'          => ['key', L10n::t('Consumer Key'), $app['client_id'], ''],
709                                 '$secret'       => ['secret', L10n::t('Consumer Secret'), $app['pw'], ''],
710                                 '$redirect'     => ['redirect', L10n::t('Redirect'), $app['redirect_uri'], ''],
711                                 '$icon'         => ['icon', L10n::t('Icon url'), $app['icon'], ''],
712                         ]);
713                         return $o;
714                 }
715
716                 if (($a->argc > 3) && ($a->argv[2] === 'delete')) {
717                         BaseModule::checkFormSecurityTokenRedirectOnError('/settings/oauth', 'settings_oauth', 't');
718
719                         DBA::delete('clients', ['client_id' => $a->argv[3], 'uid' => local_user()]);
720                         $a->internalRedirect('settings/oauth/', true);
721                         return;
722                 }
723
724                 /// @TODO validate result with DBA::isResult()
725                 $r = q("SELECT clients.*, tokens.id as oauth_token, (clients.uid=%d) AS my
726                                 FROM clients
727                                 LEFT JOIN tokens ON clients.client_id=tokens.client_id
728                                 WHERE clients.uid IN (%d, 0)",
729                                 local_user(),
730                                 local_user());
731
732
733                 $tpl = Renderer::getMarkupTemplate('settings/oauth.tpl');
734                 $o .= Renderer::replaceMacros($tpl, [
735                         '$form_security_token' => BaseModule::getFormSecurityToken("settings_oauth"),
736                         '$baseurl'      => $a->getBaseURL(true),
737                         '$title'        => L10n::t('Connected Apps'),
738                         '$add'          => L10n::t('Add application'),
739                         '$edit'         => L10n::t('Edit'),
740                         '$delete'               => L10n::t('Delete'),
741                         '$consumerkey' => L10n::t('Client key starts with'),
742                         '$noname'       => L10n::t('No name'),
743                         '$remove'       => L10n::t('Remove authorization'),
744                         '$apps'         => $r,
745                 ]);
746                 return $o;
747         }
748
749         if (($a->argc > 1) && ($a->argv[1] === 'addon')) {
750                 $settings_addons = "";
751
752                 $r = q("SELECT * FROM `hook` WHERE `hook` = 'addon_settings' ");
753                 if (!DBA::isResult($r)) {
754                         $settings_addons = L10n::t('No Addon settings configured');
755                 }
756
757                 Hook::callAll('addon_settings', $settings_addons);
758
759
760                 $tpl = Renderer::getMarkupTemplate('settings/addons.tpl');
761                 $o .= Renderer::replaceMacros($tpl, [
762                         '$form_security_token' => BaseModule::getFormSecurityToken("settings_addon"),
763                         '$title'        => L10n::t('Addon Settings'),
764                         '$settings_addons' => $settings_addons
765                 ]);
766                 return $o;
767         }
768
769         if (($a->argc > 1) && ($a->argv[1] === 'features')) {
770
771                 $arr = [];
772                 $features = Feature::get();
773                 foreach ($features as $fname => $fdata) {
774                         $arr[$fname] = [];
775                         $arr[$fname][0] = $fdata[0];
776                         foreach (array_slice($fdata,1) as $f) {
777                                 $arr[$fname][1][] = ['feature_' .$f[0], $f[1],((intval(Feature::isEnabled(local_user(), $f[0]))) ? "1" : ''), $f[2],[L10n::t('Off'), L10n::t('On')]];
778                         }
779                 }
780
781                 $tpl = Renderer::getMarkupTemplate('settings/features.tpl');
782                 $o .= Renderer::replaceMacros($tpl, [
783                         '$form_security_token' => BaseModule::getFormSecurityToken("settings_features"),
784                         '$title'               => L10n::t('Additional Features'),
785                         '$features'            => $arr,
786                         '$submit'              => L10n::t('Save Settings'),
787                 ]);
788                 return $o;
789         }
790
791         if (($a->argc > 1) && ($a->argv[1] === 'connectors')) {
792                 $accept_only_sharer        = intval(PConfig::get(local_user(), 'system', 'accept_only_sharer'));
793                 $disable_cw                = intval(PConfig::get(local_user(), 'system', 'disable_cw'));
794                 $no_intelligent_shortening = intval(PConfig::get(local_user(), 'system', 'no_intelligent_shortening'));
795                 $ostatus_autofriend        = intval(PConfig::get(local_user(), 'system', 'ostatus_autofriend'));
796                 $default_group             = PConfig::get(local_user(), 'ostatus', 'default_group');
797                 $legacy_contact            = PConfig::get(local_user(), 'ostatus', 'legacy_contact');
798
799                 if (!empty($legacy_contact)) {
800                         /// @todo Isn't it supposed to be a $a->internalRedirect() call?
801                         $a->page['htmlhead'] = '<meta http-equiv="refresh" content="0; URL=' . System::baseUrl().'/ostatus_subscribe?url=' . urlencode($legacy_contact) . '">';
802                 }
803
804                 $settings_connectors = '';
805                 Hook::callAll('connector_settings', $settings_connectors);
806
807                 if (is_site_admin()) {
808                         $diasp_enabled = L10n::t('Built-in support for %s connectivity is %s', L10n::t('Diaspora'), ((Config::get('system', 'diaspora_enabled')) ? L10n::t('enabled') : L10n::t('disabled')));
809                         $ostat_enabled = L10n::t('Built-in support for %s connectivity is %s', L10n::t("GNU Social \x28OStatus\x29"), ((Config::get('system', 'ostatus_disabled')) ? L10n::t('disabled') : L10n::t('enabled')));
810                 } else {
811                         $diasp_enabled = "";
812                         $ostat_enabled = "";
813                 }
814
815                 $mail_disabled = ((function_exists('imap_open') && (!Config::get('system', 'imap_disabled'))) ? 0 : 1);
816                 if (Config::get('system', 'dfrn_only')) {
817                         $mail_disabled = 1;
818                 }
819                 if (!$mail_disabled) {
820                         $r = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1",
821                                 local_user()
822                         );
823                 } else {
824                         $r = null;
825                 }
826
827                 $mail_server       = ((DBA::isResult($r)) ? $r[0]['server'] : '');
828                 $mail_port         = ((DBA::isResult($r) && intval($r[0]['port'])) ? intval($r[0]['port']) : '');
829                 $mail_ssl          = ((DBA::isResult($r)) ? $r[0]['ssltype'] : '');
830                 $mail_user         = ((DBA::isResult($r)) ? $r[0]['user'] : '');
831                 $mail_replyto      = ((DBA::isResult($r)) ? $r[0]['reply_to'] : '');
832                 $mail_pubmail      = ((DBA::isResult($r)) ? $r[0]['pubmail'] : 0);
833                 $mail_action       = ((DBA::isResult($r)) ? $r[0]['action'] : 0);
834                 $mail_movetofolder = ((DBA::isResult($r)) ? $r[0]['movetofolder'] : '');
835                 $mail_chk          = ((DBA::isResult($r)) ? $r[0]['last_check'] : DBA::NULL_DATETIME);
836
837
838                 $tpl = Renderer::getMarkupTemplate('settings/connectors.tpl');
839
840                 $mail_disabled_message = (($mail_disabled) ? L10n::t('Email access is disabled on this site.') : '');
841
842                 $o .= Renderer::replaceMacros($tpl, [
843                         '$form_security_token' => BaseModule::getFormSecurityToken("settings_connectors"),
844
845                         '$title'        => L10n::t('Social Networks'),
846
847                         '$diasp_enabled' => $diasp_enabled,
848                         '$ostat_enabled' => $ostat_enabled,
849
850                         '$general_settings' => L10n::t('General Social Media Settings'),
851                         '$accept_only_sharer' => ['accept_only_sharer', L10n::t('Accept only top level posts by contacts you follow'), $accept_only_sharer, L10n::t('The system does an auto completion of threads when a comment arrives. This has got the side effect that you can receive posts that had been started by a non-follower but had been commented by someone you follow. This setting deactivates this behaviour. When activated, you strictly only will receive posts from people you really do follow.')],
852                         '$disable_cw' => ['disable_cw', L10n::t('Disable Content Warning'), $disable_cw, L10n::t('Users on networks like Mastodon or Pleroma are able to set a content warning field which collapse their post by default. This disables the automatic collapsing and sets the content warning as the post title. Doesn\'t affect any other content filtering you eventually set up.')],
853                         '$no_intelligent_shortening' => ['no_intelligent_shortening', L10n::t('Disable intelligent shortening'), $no_intelligent_shortening, L10n::t('Normally the system tries to find the best link to add to shortened posts. If this option is enabled then every shortened post will always point to the original friendica post.')],
854                         '$ostatus_autofriend' => ['snautofollow', L10n::t("Automatically follow any GNU Social \x28OStatus\x29 followers/mentioners"), $ostatus_autofriend, L10n::t('If you receive a message from an unknown OStatus user, this option decides what to do. If it is checked, a new contact will be created for every unknown user.')],
855                         '$default_group' => Group::displayGroupSelection(local_user(), $default_group, L10n::t("Default group for OStatus contacts")),
856                         '$legacy_contact' => ['legacy_contact', L10n::t('Your legacy GNU Social account'), $legacy_contact, L10n::t("If you enter your old GNU Social/Statusnet account name here \x28in the format user@domain.tld\x29, your contacts will be added automatically. The field will be emptied when done.")],
857
858                         '$repair_ostatus_url' => System::baseUrl() . '/repair_ostatus',
859                         '$repair_ostatus_text' => L10n::t('Repair OStatus subscriptions'),
860
861                         '$settings_connectors' => $settings_connectors,
862
863                         '$h_imap' => L10n::t('Email/Mailbox Setup'),
864                         '$imap_desc' => L10n::t("If you wish to communicate with email contacts using this service \x28optional\x29, please specify how to connect to your mailbox."),
865                         '$imap_lastcheck' => ['imap_lastcheck', L10n::t('Last successful email check:'), $mail_chk, ''],
866                         '$mail_disabled' => $mail_disabled_message,
867                         '$mail_server'  => ['mail_server',  L10n::t('IMAP server name:'), $mail_server, ''],
868                         '$mail_port'    => ['mail_port',         L10n::t('IMAP port:'), $mail_port, ''],
869                         '$mail_ssl'             => ['mail_ssl',          L10n::t('Security:'), strtoupper($mail_ssl), '', ['notls'=>L10n::t('None'), 'TLS'=>'TLS', 'SSL'=>'SSL']],
870                         '$mail_user'    => ['mail_user',    L10n::t('Email login name:'), $mail_user, ''],
871                         '$mail_pass'    => ['mail_pass',         L10n::t('Email password:'), '', ''],
872                         '$mail_replyto' => ['mail_replyto', L10n::t('Reply-to address:'), $mail_replyto, 'Optional'],
873                         '$mail_pubmail' => ['mail_pubmail', L10n::t('Send public posts to all email contacts:'), $mail_pubmail, ''],
874                         '$mail_action'  => ['mail_action',       L10n::t('Action after import:'), $mail_action, '', [0=>L10n::t('None'), /*1=>L10n::t('Delete'),*/ 2=>L10n::t('Mark as seen'), 3=>L10n::t('Move to folder')]],
875                         '$mail_movetofolder'    => ['mail_movetofolder',         L10n::t('Move to folder:'), $mail_movetofolder, ''],
876                         '$submit' => L10n::t('Save Settings'),
877                 ]);
878
879                 Hook::callAll('display_settings', $o);
880                 return $o;
881         }
882
883         /*
884          * DISPLAY SETTINGS
885          */
886         if (($a->argc > 1) && ($a->argv[1] === 'display')) {
887                 $default_theme = Config::get('system', 'theme');
888                 if (!$default_theme) {
889                         $default_theme = 'default';
890                 }
891                 $default_mobile_theme = Config::get('system', 'mobile-theme');
892                 if (!$default_mobile_theme) {
893                         $default_mobile_theme = 'none';
894                 }
895
896                 $allowed_themes = Theme::getAllowedList();
897
898                 $themes = [];
899                 $mobile_themes = ["---" => L10n::t('No special theme for mobile devices')];
900                 foreach ($allowed_themes as $theme) {
901                         $is_experimental = file_exists('view/theme/' . $theme . '/experimental');
902                         $is_unsupported  = file_exists('view/theme/' . $theme . '/unsupported');
903                         $is_mobile       = file_exists('view/theme/' . $theme . '/mobile');
904                         if (!$is_experimental || ($is_experimental && (Config::get('experimentals', 'exp_themes')==1 || is_null(Config::get('experimentals', 'exp_themes'))))) {
905                                 $theme_name = ucfirst($theme);
906                                 if ($is_unsupported) {
907                                         $theme_name = L10n::t('%s - (Unsupported)', $theme_name);
908                                 } elseif ($is_experimental) {
909                                         $theme_name = L10n::t('%s - (Experimental)', $theme_name);
910                                 }
911
912                                 if ($is_mobile) {
913                                         $mobile_themes[$theme] = $theme_name;
914                                 } else {
915                                         $themes[$theme] = $theme_name;
916                                 }
917                         }
918                 }
919
920                 $theme_selected        = $a->user['theme'] ?: $default_theme;
921                 $mobile_theme_selected = Session::get('mobile-theme', $default_mobile_theme);
922
923                 $nowarn_insecure = intval(PConfig::get(local_user(), 'system', 'nowarn_insecure'));
924
925                 $browser_update = intval(PConfig::get(local_user(), 'system', 'update_interval'));
926                 if (intval($browser_update) != -1) {
927                         $browser_update = (($browser_update == 0) ? 40 : $browser_update / 1000); // default if not set: 40 seconds
928                 }
929
930                 $itemspage_network = intval(PConfig::get(local_user(), 'system', 'itemspage_network'));
931                 $itemspage_network = (($itemspage_network > 0 && $itemspage_network < 101) ? $itemspage_network : 40); // default if not set: 40 items
932                 $itemspage_mobile_network = intval(PConfig::get(local_user(), 'system', 'itemspage_mobile_network'));
933                 $itemspage_mobile_network = (($itemspage_mobile_network > 0 && $itemspage_mobile_network < 101) ? $itemspage_mobile_network : 20); // default if not set: 20 items
934
935                 $nosmile = PConfig::get(local_user(), 'system', 'no_smilies', 0);
936                 $first_day_of_week = PConfig::get(local_user(), 'system', 'first_day_of_week', 0);
937                 $weekdays = [0 => L10n::t("Sunday"), 1 => L10n::t("Monday")];
938
939                 $noinfo = PConfig::get(local_user(), 'system', 'ignore_info', 0);
940                 $infinite_scroll = PConfig::get(local_user(), 'system', 'infinite_scroll', 0);
941                 $no_auto_update = PConfig::get(local_user(), 'system', 'no_auto_update', 0);
942                 $bandwidth_saver = PConfig::get(local_user(), 'system', 'bandwidth_saver', 0);
943                 $smart_threading = PConfig::get(local_user(), 'system', 'smart_threading', 0);
944
945                 $theme_config = "";
946                 if (($themeconfigfile = get_theme_config_file($theme_selected)) !== null) {
947                         require_once $themeconfigfile;
948                         $theme_config = theme_content($a);
949                 }
950
951                 $tpl = Renderer::getMarkupTemplate('settings/display.tpl');
952                 $o = Renderer::replaceMacros($tpl, [
953                         '$ptitle'       => L10n::t('Display Settings'),
954                         '$form_security_token' => BaseModule::getFormSecurityToken("settings_display"),
955                         '$submit'       => L10n::t('Save Settings'),
956                         '$baseurl' => System::baseUrl(true),
957                         '$uid' => local_user(),
958
959                         '$theme'        => ['theme', L10n::t('Display Theme:'), $theme_selected, '', $themes, true],
960                         '$mobile_theme' => ['mobile_theme', L10n::t('Mobile Theme:'), $mobile_theme_selected, '', $mobile_themes, false],
961                         '$nowarn_insecure' => ['nowarn_insecure',  L10n::t('Suppress warning of insecure networks'), $nowarn_insecure, L10n::t("Should the system suppress the warning that the current group contains members of networks that can't receive non public postings.")],
962                         '$ajaxint'   => ['browser_update',  L10n::t("Update browser every xx seconds"), $browser_update, L10n::t('Minimum of 10 seconds. Enter -1 to disable it.')],
963                         '$itemspage_network'   => ['itemspage_network',  L10n::t("Number of items to display per page:"), $itemspage_network, L10n::t('Maximum of 100 items')],
964                         '$itemspage_mobile_network'   => ['itemspage_mobile_network',  L10n::t("Number of items to display per page when viewed from mobile device:"), $itemspage_mobile_network, L10n::t('Maximum of 100 items')],
965                         '$nosmile'      => ['nosmile', L10n::t("Don't show emoticons"), $nosmile, ''],
966                         '$calendar_title' => L10n::t('Calendar'),
967                         '$first_day_of_week'    => ['first_day_of_week', L10n::t('Beginning of week:'), $first_day_of_week, '', $weekdays, false],
968                         '$noinfo'       => ['noinfo', L10n::t("Don't show notices"), $noinfo, ''],
969                         '$infinite_scroll'      => ['infinite_scroll', L10n::t("Infinite scroll"), $infinite_scroll, ''],
970                         '$no_auto_update'       => ['no_auto_update', L10n::t("Automatic updates only at the top of the network page"), $no_auto_update, L10n::t('When disabled, the network page is updated all the time, which could be confusing while reading.')],
971                         '$bandwidth_saver' => ['bandwidth_saver', L10n::t('Bandwidth Saver Mode'), $bandwidth_saver, L10n::t('When enabled, embedded content is not displayed on automatic updates, they only show on page reload.')],
972                         '$smart_threading' => ['smart_threading', L10n::t('Smart Threading'), $smart_threading, L10n::t('When enabled, suppress extraneous thread indentation while keeping it where it matters. Only works if threading is available and enabled.')],
973
974                         '$d_tset' => L10n::t('General Theme Settings'),
975                         '$d_ctset' => L10n::t('Custom Theme Settings'),
976                         '$d_cset' => L10n::t('Content Settings'),
977                         'stitle' => L10n::t('Theme settings'),
978                         '$theme_config' => $theme_config,
979                 ]);
980
981                 return $o;
982         }
983
984
985         /*
986          * ACCOUNT SETTINGS
987          */
988
989         $profile = DBA::selectFirst('profile', [], ['is-default' => true, 'uid' => local_user()]);
990         if (!DBA::isResult($profile)) {
991                 notice(L10n::t('Unable to find your profile. Please contact your admin.') . EOL);
992                 return;
993         }
994
995         $username   = $a->user['username'];
996         $email      = $a->user['email'];
997         $nickname   = $a->user['nickname'];
998         $timezone   = $a->user['timezone'];
999         $language   = $a->user['language'];
1000         $notify     = $a->user['notify-flags'];
1001         $defloc     = $a->user['default-location'];
1002         $openid     = $a->user['openid'];
1003         $maxreq     = $a->user['maxreq'];
1004         $expire     = ((intval($a->user['expire'])) ? $a->user['expire'] : '');
1005         $unkmail    = $a->user['unkmail'];
1006         $cntunkmail = $a->user['cntunkmail'];
1007
1008         $expire_items = PConfig::get(local_user(), 'expire', 'items', true);
1009         $expire_notes = PConfig::get(local_user(), 'expire', 'notes', true);
1010         $expire_starred = PConfig::get(local_user(), 'expire', 'starred', true);
1011         $expire_photos = PConfig::get(local_user(), 'expire', 'photos', false);
1012         $expire_network_only = PConfig::get(local_user(), 'expire', 'network_only', false);
1013         $suggestme = PConfig::get(local_user(), 'system', 'suggestme', false);
1014
1015         // nowarn_insecure
1016
1017         if (!strlen($a->user['timezone'])) {
1018                 $timezone = date_default_timezone_get();
1019         }
1020
1021         // Set the account type to "Community" when the page is a community page but the account type doesn't fit
1022         // This is only happening on the first visit after the update
1023         if (in_array($a->user['page-flags'], [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP]) &&
1024                 ($a->user['account-type'] != User::ACCOUNT_TYPE_COMMUNITY))
1025                 $a->user['account-type'] = User::ACCOUNT_TYPE_COMMUNITY;
1026
1027         $pageset_tpl = Renderer::getMarkupTemplate('settings/pagetypes.tpl');
1028
1029         $pagetype = Renderer::replaceMacros($pageset_tpl, [
1030                 '$account_types'        => L10n::t("Account Types"),
1031                 '$user'                 => L10n::t("Personal Page Subtypes"),
1032                 '$community'            => L10n::t("Community Forum Subtypes"),
1033                 '$account_type'         => $a->user['account-type'],
1034                 '$type_person'          => User::ACCOUNT_TYPE_PERSON,
1035                 '$type_organisation'    => User::ACCOUNT_TYPE_ORGANISATION,
1036                 '$type_news'            => User::ACCOUNT_TYPE_NEWS,
1037                 '$type_community'       => User::ACCOUNT_TYPE_COMMUNITY,
1038
1039                 '$account_person'       => ['account-type', L10n::t('Personal Page'), User::ACCOUNT_TYPE_PERSON,
1040                                                                         L10n::t('Account for a personal profile.'),
1041                                                                         ($a->user['account-type'] == User::ACCOUNT_TYPE_PERSON)],
1042
1043                 '$account_organisation' => ['account-type', L10n::t('Organisation Page'), User::ACCOUNT_TYPE_ORGANISATION,
1044                                                                         L10n::t('Account for an organisation that automatically approves contact requests as "Followers".'),
1045                                                                         ($a->user['account-type'] == User::ACCOUNT_TYPE_ORGANISATION)],
1046
1047                 '$account_news'         => ['account-type', L10n::t('News Page'), User::ACCOUNT_TYPE_NEWS,
1048                                                                         L10n::t('Account for a news reflector that automatically approves contact requests as "Followers".'),
1049                                                                         ($a->user['account-type'] == User::ACCOUNT_TYPE_NEWS)],
1050
1051                 '$account_community'    => ['account-type', L10n::t('Community Forum'), User::ACCOUNT_TYPE_COMMUNITY,
1052                                                                         L10n::t('Account for community discussions.'),
1053                                                                         ($a->user['account-type'] == User::ACCOUNT_TYPE_COMMUNITY)],
1054
1055                 '$page_normal'          => ['page-flags', L10n::t('Normal Account Page'), User::PAGE_FLAGS_NORMAL,
1056                                                                         L10n::t('Account for a regular personal profile that requires manual approval of "Friends" and "Followers".'),
1057                                                                         ($a->user['page-flags'] == User::PAGE_FLAGS_NORMAL)],
1058
1059                 '$page_soapbox'         => ['page-flags', L10n::t('Soapbox Page'), User::PAGE_FLAGS_SOAPBOX,
1060                                                                         L10n::t('Account for a public profile that automatically approves contact requests as "Followers".'),
1061                                                                         ($a->user['page-flags'] == User::PAGE_FLAGS_SOAPBOX)],
1062
1063                 '$page_community'       => ['page-flags', L10n::t('Public Forum'), User::PAGE_FLAGS_COMMUNITY,
1064                                                                         L10n::t('Automatically approves all contact requests.'),
1065                                                                         ($a->user['page-flags'] == User::PAGE_FLAGS_COMMUNITY)],
1066
1067                 '$page_freelove'        => ['page-flags', L10n::t('Automatic Friend Page'), User::PAGE_FLAGS_FREELOVE,
1068                                                                         L10n::t('Account for a popular profile that automatically approves contact requests as "Friends".'),
1069                                                                         ($a->user['page-flags'] == User::PAGE_FLAGS_FREELOVE)],
1070
1071                 '$page_prvgroup'        => ['page-flags', L10n::t('Private Forum [Experimental]'), User::PAGE_FLAGS_PRVGROUP,
1072                                                                         L10n::t('Requires manual approval of contact requests.'),
1073                                                                         ($a->user['page-flags'] == User::PAGE_FLAGS_PRVGROUP)],
1074
1075
1076         ]);
1077
1078         $noid = Config::get('system', 'no_openid');
1079
1080         if ($noid) {
1081                 $openid_field = false;
1082         } else {
1083                 $openid_field = ['openid_url', L10n::t('OpenID:'), $openid, L10n::t("\x28Optional\x29 Allow this OpenID to login to this account."), "", "", "url"];
1084         }
1085
1086         $opt_tpl = Renderer::getMarkupTemplate("field_yesno.tpl");
1087         if (Config::get('system', 'publish_all')) {
1088                 $profile_in_dir = '<input type="hidden" name="profile_in_directory" value="1" />';
1089         } else {
1090                 $profile_in_dir = Renderer::replaceMacros($opt_tpl, [
1091                         '$field' => ['profile_in_directory', L10n::t('Publish your default profile in your local site directory?'), $profile['publish'], L10n::t('Your profile will be published in this node\'s <a href="%s">local directory</a>. Your profile details may be publicly visible depending on the system settings.', System::baseUrl().'/directory'), [L10n::t('No'), L10n::t('Yes')]]
1092                 ]);
1093         }
1094
1095         if (strlen(Config::get('system', 'directory'))) {
1096                 $profile_in_net_dir = Renderer::replaceMacros($opt_tpl, [
1097                         '$field' => ['profile_in_netdirectory', L10n::t('Publish your default profile in the global social directory?'), $profile['net-publish'], L10n::t('Your profile will be published in the global friendica directories (e.g. <a href="%s">%s</a>). Your profile will be visible in public.', Config::get('system', 'directory'), Config::get('system', 'directory'))     . " " . L10n::t("This setting also determines whether Friendica will inform search engines that your profile should be indexed or not. Third-party search engines may or may not respect this setting."), [L10n::t('No'), L10n::t('Yes')]]
1098                 ]);
1099         } else {
1100                 $profile_in_net_dir = '';
1101         }
1102
1103         $hide_friends = Renderer::replaceMacros($opt_tpl, [
1104                 '$field' => ['hide-friends', L10n::t('Hide your contact/friend list from viewers of your default profile?'), $profile['hide-friends'], L10n::t('Your contact list won\'t be shown in your default profile page. You can decide to show your contact list separately for each additional profile you create'), [L10n::t('No'), L10n::t('Yes')]],
1105         ]);
1106
1107         $hide_wall = Renderer::replaceMacros($opt_tpl, [
1108                 '$field' => ['hidewall', L10n::t('Hide your profile details from anonymous viewers?'), $a->user['hidewall'], L10n::t('Anonymous visitors will only see your profile picture, your display name and the nickname you are using on your profile page. Your public posts and replies will still be accessible by other means.'), [L10n::t('No'), L10n::t('Yes')]],
1109         ]);
1110
1111         $blockwall = Renderer::replaceMacros($opt_tpl, [
1112                 '$field' => ['blockwall', L10n::t('Allow friends to post to your profile page?'), (intval($a->user['blockwall']) ? '0' : '1'), L10n::t('Your contacts may write posts on your profile wall. These posts will be distributed to your contacts'), [L10n::t('No'), L10n::t('Yes')]],
1113         ]);
1114
1115         $blocktags = Renderer::replaceMacros($opt_tpl, [
1116                 '$field' => ['blocktags', L10n::t('Allow friends to tag your posts?'), (intval($a->user['blocktags']) ? '0' : '1'), L10n::t('Your contacts can add additional tags to your posts.'), [L10n::t('No'), L10n::t('Yes')]],
1117         ]);
1118
1119         $suggestme = Renderer::replaceMacros($opt_tpl, [
1120                 '$field' => ['suggestme', L10n::t('Allow us to suggest you as a potential friend to new members?'), $suggestme, L10n::t('If you like, Friendica may suggest new members to add you as a contact.'), [L10n::t('No'), L10n::t('Yes')]],
1121         ]);
1122
1123         $unkmail = Renderer::replaceMacros($opt_tpl, [
1124                 '$field' => ['unkmail', L10n::t('Permit unknown people to send you private mail?'), $unkmail, L10n::t('Friendica network users may send you private messages even if they are not in your contact list.'), [L10n::t('No'), L10n::t('Yes')]],
1125         ]);
1126
1127         if (!$profile['publish'] && !$profile['net-publish']) {
1128                 info(L10n::t('Profile is <strong>not published</strong>.') . EOL);
1129         }
1130
1131         $tpl_addr = Renderer::getMarkupTemplate('settings/nick_set.tpl');
1132
1133         $prof_addr = Renderer::replaceMacros($tpl_addr,[
1134                 '$desc' => L10n::t("Your Identity Address is <strong>'%s'</strong> or '%s'.", $nickname . '@' . $a->getHostName() . $a->getURLPath(), System::baseUrl() . '/profile/' . $nickname),
1135                 '$basepath' => $a->getHostName()
1136         ]);
1137
1138         $stpl = Renderer::getMarkupTemplate('settings/settings.tpl');
1139
1140         $expire_arr = [
1141                 'days' => ['expire',  L10n::t("Automatically expire posts after this many days:"), $expire, L10n::t('If empty, posts will not expire. Expired posts will be deleted')],
1142                 'advanced' => L10n::t('Advanced expiration settings'),
1143                 'label' => L10n::t('Advanced Expiration'),
1144                 'items' => ['expire_items',  L10n::t("Expire posts:"), $expire_items, '', [L10n::t('No'), L10n::t('Yes')]],
1145                 'notes' => ['expire_notes',  L10n::t("Expire personal notes:"), $expire_notes, '', [L10n::t('No'), L10n::t('Yes')]],
1146                 'starred' => ['expire_starred',  L10n::t("Expire starred posts:"), $expire_starred, '', [L10n::t('No'), L10n::t('Yes')]],
1147                 'photos' => ['expire_photos',  L10n::t("Expire photos:"), $expire_photos, '', [L10n::t('No'), L10n::t('Yes')]],
1148                 'network_only' => ['expire_network_only',  L10n::t("Only expire posts by others:"), $expire_network_only, '', [L10n::t('No'), L10n::t('Yes')]],
1149         ];
1150
1151         $group_select = Group::displayGroupSelection(local_user(), $a->user['def_gid']);
1152
1153         // Private/public post links for the non-JS ACL form
1154         $private_post = 1;
1155         if (!empty($_REQUEST['public']) && !$_REQUEST['public']) {
1156                 $private_post = 0;
1157         }
1158
1159         $query_str = $a->query_string;
1160         if (strpos($query_str, 'public=1') !== false) {
1161                 $query_str = str_replace(['?public=1', '&public=1'], ['', ''], $query_str);
1162         }
1163
1164         // I think $a->query_string may never have ? in it, but I could be wrong
1165         // It looks like it's from the index.php?q=[etc] rewrite that the web
1166         // server does, which converts any ? to &, e.g. suggest&ignore=61 for suggest?ignore=61
1167         if (strpos($query_str, '?') === false) {
1168                 $public_post_link = '?public=1';
1169         } else {
1170                 $public_post_link = '&public=1';
1171         }
1172
1173         /* Installed langs */
1174         $lang_choices = L10n::getAvailableLanguages();
1175
1176         /// @TODO Fix indending (or so)
1177         $o .= Renderer::replaceMacros($stpl, [
1178                 '$ptitle'       => L10n::t('Account Settings'),
1179
1180                 '$submit'       => L10n::t('Save Settings'),
1181                 '$baseurl' => System::baseUrl(true),
1182                 '$uid' => local_user(),
1183                 '$form_security_token' => BaseModule::getFormSecurityToken("settings"),
1184                 '$nickname_block' => $prof_addr,
1185
1186                 '$h_pass'       => L10n::t('Password Settings'),
1187                 '$password1'=> ['password', L10n::t('New Password:'), '', L10n::t('Allowed characters are a-z, A-Z, 0-9 and special characters except white spaces, accentuated letters and colon (:).')],
1188                 '$password2'=> ['confirm', L10n::t('Confirm:'), '', L10n::t('Leave password fields blank unless changing')],
1189                 '$password3'=> ['opassword', L10n::t('Current Password:'), '', L10n::t('Your current password to confirm the changes')],
1190                 '$password4'=> ['mpassword', L10n::t('Password:'), '', L10n::t('Your current password to confirm the changes')],
1191                 '$oid_enable' => (!Config::get('system', 'no_openid')),
1192                 '$openid'       => $openid_field,
1193
1194                 '$h_basic'      => L10n::t('Basic Settings'),
1195                 '$username' => ['username',  L10n::t('Full Name:'), $username, ''],
1196                 '$email'        => ['email', L10n::t('Email Address:'), $email, '', '', '', 'email'],
1197                 '$timezone' => ['timezone_select' , L10n::t('Your Timezone:'), Temporal::getTimezoneSelect($timezone), ''],
1198                 '$language' => ['language', L10n::t('Your Language:'), $language, L10n::t('Set the language we use to show you friendica interface and to send you emails'), $lang_choices],
1199                 '$defloc'       => ['defloc', L10n::t('Default Post Location:'), $defloc, ''],
1200                 '$allowloc' => ['allow_location', L10n::t('Use Browser Location:'), ($a->user['allow_location'] == 1), ''],
1201
1202
1203                 '$h_prv'        => L10n::t('Security and Privacy Settings'),
1204
1205                 '$maxreq'       => ['maxreq', L10n::t('Maximum Friend Requests/Day:'), $maxreq , L10n::t("\x28to prevent spam abuse\x29")],
1206                 '$permissions' => L10n::t('Default Post Permissions'),
1207                 '$permdesc' => L10n::t("\x28click to open/close\x29"),
1208                 '$visibility' => $profile['net-publish'],
1209                 '$aclselect' => ACL::getFullSelectorHTML($a->user),
1210                 '$suggestme' => $suggestme,
1211                 '$blockwall'=> $blockwall, // array('blockwall', L10n::t('Allow friends to post to your profile page:'), !$blockwall, ''),
1212                 '$blocktags'=> $blocktags, // array('blocktags', L10n::t('Allow friends to tag your posts:'), !$blocktags, ''),
1213
1214                 // ACL permissions box
1215                 '$group_perms' => L10n::t('Show to Groups'),
1216                 '$contact_perms' => L10n::t('Show to Contacts'),
1217                 '$private' => L10n::t('Default Private Post'),
1218                 '$public' => L10n::t('Default Public Post'),
1219                 '$is_private' => $private_post,
1220                 '$return_path' => $query_str,
1221                 '$public_link' => $public_post_link,
1222                 '$settings_perms' => L10n::t('Default Permissions for New Posts'),
1223
1224                 '$group_select' => $group_select,
1225
1226
1227                 '$expire'       => $expire_arr,
1228
1229                 '$profile_in_dir' => $profile_in_dir,
1230                 '$profile_in_net_dir' => $profile_in_net_dir,
1231                 '$hide_friends' => $hide_friends,
1232                 '$hide_wall' => $hide_wall,
1233                 '$unkmail' => $unkmail,
1234                 '$cntunkmail'   => ['cntunkmail', L10n::t('Maximum private messages per day from unknown people:'), $cntunkmail , L10n::t("\x28to prevent spam abuse\x29")],
1235
1236
1237                 '$h_not'        => L10n::t('Notification Settings'),
1238                 '$lbl_not'      => L10n::t('Send a notification email when:'),
1239                 '$notify1'      => ['notify1', L10n::t('You receive an introduction'), ($notify & NOTIFY_INTRO), NOTIFY_INTRO, ''],
1240                 '$notify2'      => ['notify2', L10n::t('Your introductions are confirmed'), ($notify & NOTIFY_CONFIRM), NOTIFY_CONFIRM, ''],
1241                 '$notify3'      => ['notify3', L10n::t('Someone writes on your profile wall'), ($notify & NOTIFY_WALL), NOTIFY_WALL, ''],
1242                 '$notify4'      => ['notify4', L10n::t('Someone writes a followup comment'), ($notify & NOTIFY_COMMENT), NOTIFY_COMMENT, ''],
1243                 '$notify5'      => ['notify5', L10n::t('You receive a private message'), ($notify & NOTIFY_MAIL), NOTIFY_MAIL, ''],
1244                 '$notify6'  => ['notify6', L10n::t('You receive a friend suggestion'), ($notify & NOTIFY_SUGGEST), NOTIFY_SUGGEST, ''],
1245                 '$notify7'  => ['notify7', L10n::t('You are tagged in a post'), ($notify & NOTIFY_TAGSELF), NOTIFY_TAGSELF, ''],
1246                 '$notify8'  => ['notify8', L10n::t('You are poked/prodded/etc. in a post'), ($notify & NOTIFY_POKE), NOTIFY_POKE, ''],
1247
1248                 '$desktop_notifications' => ['desktop_notifications', L10n::t('Activate desktop notifications') , false, L10n::t('Show desktop popup on new notifications')],
1249
1250                 '$email_textonly' => ['email_textonly', L10n::t('Text-only notification emails'),
1251                                                                         PConfig::get(local_user(), 'system', 'email_textonly'),
1252                                                                         L10n::t('Send text only notification emails, without the html part')],
1253
1254                 '$detailed_notif' => ['detailed_notif', L10n::t('Show detailled notifications'),
1255                                                                         PConfig::get(local_user(), 'system', 'detailed_notif'),
1256                                                                         L10n::t('Per default, notifications are condensed to a single notification per item. When enabled every notification is displayed.')],
1257
1258                 '$h_advn' => L10n::t('Advanced Account/Page Type Settings'),
1259                 '$h_descadvn' => L10n::t('Change the behaviour of this account for special situations'),
1260                 '$pagetype' => $pagetype,
1261
1262                 '$relocate' => L10n::t('Relocate'),
1263                 '$relocate_text' => L10n::t("If you have moved this profile from another server, and some of your contacts don't receive your updates, try pushing this button."),
1264                 '$relocate_button' => L10n::t("Resend relocate message to contacts"),
1265
1266         ]);
1267
1268         Hook::callAll('settings_form', $o);
1269
1270         $o .= '</form>' . "\r\n";
1271
1272         return $o;
1273
1274 }