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