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