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