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