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