We are no longer offering accounts on this server. Consider https://gitlab.freedesktop.org/ as a place to host projects.

emailsettings.php 21.6 KB
Newer Older
1
<?php
2
/**
3
 * StatusNet, the distributed open-source microblogging tool
4
 *
5 6 7 8 9
 * Settings for email
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
10 11 12 13 14 15 16 17 18 19 20
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 22
 *
 * @category  Settings
23
 * @package   StatusNet
24 25
 * @author    Evan Prodromou <evan@status.net>
 * @author    Zach Copley <zach@status.net>
26
 * @copyright 2008-2009 StatusNet, Inc.
27
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
28
 * @link      http://status.net/
29 30
 */

31
if (!defined('STATUSNET') && !defined('LACONICA')) {
32 33
    exit(1);
}
34

35

36 37 38 39 40

/**
 * Settings for email
 *
 * @category Settings
41
 * @package  StatusNet
42 43
 * @author   Evan Prodromou <evan@status.net>
 * @author   Zach Copley <zach@status.net>
44
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
45
 * @link     http://status.net/
46 47 48
 *
 * @see      Widget
 */
49

50
class EmailsettingsAction extends SettingsAction
51
{
52 53 54 55 56 57 58
    /**
     * Title of the page
     *
     * @return string Title of the page
     */
    function title()
    {
59
        // TRANS: Title for e-mail settings.
60
        return _('Email settings');
61 62 63 64 65 66 67 68
    }

    /**
     * Instructions for use
     *
     * @return instructions for use
     */
    function getInstructions()
69
    {
70 71 72 73
        // XXX: For consistency of parameters in messages, this should be a
        //      regular parameters, replaced with sprintf().
        // TRANS: E-mail settings page instructions.
        // TRANS: %%site.name%% is the name of the site.
74 75 76
        return _('Manage how you get email from %%site.name%%.');
    }

77 78 79
    function showScripts()
    {
        parent::showScripts();
80
        $this->script('emailsettings.js');
81 82 83
        $this->autofocus('email');
    }

84 85 86 87 88 89 90 91 92
    /**
     * Content area of the page
     *
     * Shows a form for adding and removing email addresses and setting
     * email preferences.
     *
     * @return void
     */
    function showContent()
93
    {
94
        $user = common_current_user();
95

96
        $this->elementStart('form', array('method' => 'post',
sarven's avatar
sarven committed
97 98
                                          'id' => 'form_settings_email',
                                          'class' => 'form_settings',
99 100
                                          'action' =>
                                          common_local_url('emailsettings')));
101
        $this->elementStart('fieldset');
sarven's avatar
sarven committed
102
        $this->elementStart('fieldset', array('id' => 'settings_email_address'));
103 104
        // TRANS: Form legend for e-mail settings form.
        $this->element('legend', null, _('Email address'));
sarven's avatar
sarven committed
105
        $this->hidden('token', common_session_token());
106 107

        if ($user->email) {
sarven's avatar
sarven committed
108
            $this->element('p', array('id' => 'form_confirmed'), $user->email);
109
            // TRANS: Form note in e-mail settings form.
sarven's avatar
sarven committed
110
            $this->element('p', array('class' => 'form_note'), _('Current confirmed email address.'));
111
            $this->hidden('email', $user->email);
112 113
            // TRANS: Button label to remove a confirmed e-mail address.
            $this->submit('remove', _m('BUTTON','Remove'));
114
        } else {
115
            $confirm = $this->getConfirmation();
116
            if ($confirm) {
sarven's avatar
sarven committed
117
                $this->element('p', array('id' => 'form_unconfirmed'), $confirm->address);
118
                $this->element('p', array('class' => 'form_note'),
119
                                        // TRANS: Form note in e-mail settings form.
sarven's avatar
sarven committed
120 121 122
                                        _('Awaiting confirmation on this address. '.
                                        'Check your inbox (and spam box!) for a message '.
                                        'with further instructions.'));
123
                $this->hidden('email', $confirm->address);
124 125
                // TRANS: Button label to cancel an e-mail address confirmation procedure.
                $this->submit('cancel', _m('BUTTON','Cancel'));
126
            } else {
sarven's avatar
sarven committed
127
                $this->elementStart('ul', 'form_data');
sarven's avatar
sarven committed
128
                $this->elementStart('li');
129
                // TRANS: Field label for e-mail address input in e-mail settings form.
130
                $this->input('email', _('Email address'),
Evan Prodromou's avatar
Evan Prodromou committed
131
                             ($this->arg('email')) ? $this->arg('email') : null,
132 133 134 135 136
                             // TRANS: Instructions for e-mail address input form. Do not translate
                             // TRANS: "example.org". It is one of the domain names reserved for
                             // TRANS: use in examples by http://www.rfc-editor.org/rfc/rfc2606.txt.
                             // TRANS: Any other domain may be owned by a legitimate person or
                             // TRANS: organization.
137
                             _('Email address, like "UserName@example.org"'));
sarven's avatar
sarven committed
138 139
                $this->elementEnd('li');
                $this->elementEnd('ul');
140 141
                // TRANS: Button label for adding an e-mail address in e-mail settings form.
                $this->submit('add', _m('BUTTON','Add'));
142 143
            }
        }
sarven's avatar
sarven committed
144
        $this->elementEnd('fieldset');
145

146
       if (common_config('emailpost', 'enabled') && $user->email) {
sarven's avatar
sarven committed
147
            $this->elementStart('fieldset', array('id' => 'settings_email_incoming'));
148
            // TRANS: Form legend for incoming e-mail settings form.
149
            $this->element('legend', null, _('Incoming email'));
150 151 152 153 154 155 156 157 158 159

            $this->elementStart('ul', 'form_data');
            $this->elementStart('li');
            $this->checkbox('emailpost',
                    // TRANS: Checkbox label in e-mail preferences form.
                    _('I want to post notices by email.'),
                    $user->emailpost);
            $this->elementEnd('li');
            $this->elementEnd('ul');

160 161 162 163 164 165 166 167 168 169
            // Our stylesheets make the form_data list items all floats, which
            // creates lots of problems with trying to wrap divs around things.
            // This should force a break before the next section, which needs
            // to be separate so we can disable the things in it when the
            // checkbox is off.
            $this->elementStart('div', array('style' => 'clear: both'));
            $this->elementEnd('div');

            $this->elementStart('div', array('id' => 'emailincoming'));

170
            if ($user->incomingemail) {
171 172
                $this->elementStart('p');
                $this->element('span', 'address', $user->incomingemail);
173
                // @todo XXX: Looks a little awkward in the UI.
174
                //      Something like "xxxx@identi.ca  Send email ..". Needs improvement.
175
                $this->element('span', 'input_instructions',
176
                               // TRANS: Form instructions for incoming e-mail form in e-mail settings.
177
                               _('Send email to this address to post new notices.'));
178
                $this->elementEnd('p');
179 180
                // TRANS: Button label for removing a set sender e-mail address to post notices from.
                $this->submit('removeincoming', _m('BUTTON','Remove'));
181
            }
182

183
            $this->elementStart('p');
184 185 186 187 188 189 190 191 192
            if ($user->incomingemail) {
                // TRANS: Instructions for incoming e-mail address input form, when an address has already been assigned.
                $msg = _('Make a new email address for posting to; '.
                         'cancels the old one.');
            } else {
                // TRANS: Instructions for incoming e-mail address input form.
                $msg = _('To send notices via email, we need to create a unique email address for you on this server:');
            }
            $this->element('span', 'input_instructions', $msg);
193
            $this->elementEnd('p');
194

195 196
            // TRANS: Button label for adding an e-mail address to send notices from.
            $this->submit('newincoming', _m('BUTTON','New'));
197 198 199

            $this->elementEnd('div'); // div#emailincoming

sarven's avatar
sarven committed
200
            $this->elementEnd('fieldset');
201
        }
202

sarven's avatar
sarven committed
203
        $this->elementStart('fieldset', array('id' => 'settings_email_preferences'));
204 205
        // TRANS: Form legend for e-mail preferences form.
        $this->element('legend', null, _('Email preferences'));
206

sarven's avatar
sarven committed
207
        $this->elementStart('ul', 'form_data');
208

209
        if (Event::handle('StartEmailFormData', array($this))) {
Siebrand Mazeland's avatar
Siebrand Mazeland committed
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
            $this->elementStart('li');
            $this->checkbox('emailnotifysub',
                            // TRANS: Checkbox label in e-mail preferences form.
                            _('Send me notices of new subscriptions through email.'),
                            $user->emailnotifysub);
            $this->elementEnd('li');
            $this->elementStart('li');
            $this->checkbox('emailnotifyfav',
                            // TRANS: Checkbox label in e-mail preferences form.
                            _('Send me email when someone '.
                              'adds my notice as a favorite.'),
                            $user->emailnotifyfav);
            $this->elementEnd('li');
            $this->elementStart('li');
            $this->checkbox('emailnotifymsg',
                            // TRANS: Checkbox label in e-mail preferences form.
                            _('Send me email when someone sends me a private message.'),
                            $user->emailnotifymsg);
            $this->elementEnd('li');
            $this->elementStart('li');
            $this->checkbox('emailnotifyattn',
                            // TRANS: Checkbox label in e-mail preferences form.
                            _('Send me email when someone sends me an "@-reply".'),
                            $user->emailnotifyattn);
            $this->elementEnd('li');
            $this->elementStart('li');
            $this->checkbox('emailnotifynudge',
                            // TRANS: Checkbox label in e-mail preferences form.
                            _('Allow friends to nudge me and send me an email.'),
                            $user->emailnotifynudge);
            $this->elementEnd('li');
            $this->elementStart('li');
            $this->checkbox('emailmicroid',
                            // TRANS: Checkbox label in e-mail preferences form.
                            _('Publish a MicroID for my email address.'),
                            $user->emailmicroid);
            $this->elementEnd('li');
            Event::handle('EndEmailFormData', array($this));
        }
sarven's avatar
sarven committed
249
        $this->elementEnd('ul');
250 251
        // TRANS: Button label to save e-mail preferences.
        $this->submit('save', _m('BUTTON','Save'));
sarven's avatar
sarven committed
252
        $this->elementEnd('fieldset');
253
        $this->elementEnd('fieldset');
254
        $this->elementEnd('form');
255 256
    }

257 258 259 260 261 262
    /**
     * Gets any existing email address confirmations we're waiting for
     *
     * @return Confirm_address Email address confirmation for user, or null
     */
    function getConfirmation()
263
    {
264
        $user = common_current_user();
265

266
        $confirm = new Confirm_address();
267 268

        $confirm->user_id      = $user->id;
269
        $confirm->address_type = 'email';
270

Evan Prodromou's avatar
TRUE  
Evan Prodromou committed
271
        if ($confirm->find(true)) {
272 273
            return $confirm;
        } else {
Evan Prodromou's avatar
Evan Prodromou committed
274
            return null;
275 276 277
        }
    }

278 279 280 281 282 283 284 285 286 287
    /**
     * Handle posts
     *
     * Since there are a lot of different options on the page, we
     * figure out what we're supposed to do based on which button was
     * pushed
     *
     * @return void
     */
    function handlePost()
288
    {
289
        // CSRF protection
290 291
        $token = $this->trimmed('token');
        if (!$token || $token != common_session_token()) {
292
            // TRANS: Client error displayed when the session token does not match or is not given.
293 294
            $this->show_form(_('There was a problem with your session token. '.
                               'Try again, please.'));
295 296 297 298
            return;
        }

        if ($this->arg('save')) {
299
            $this->savePreferences();
300
        } else if ($this->arg('add')) {
301
            $this->addAddress();
302
        } else if ($this->arg('cancel')) {
303
            $this->cancelConfirmation();
304
        } else if ($this->arg('remove')) {
305
            $this->removeAddress();
306
        } else if ($this->arg('removeincoming')) {
307
            $this->removeIncoming();
308
        } else if ($this->arg('newincoming')) {
309
            $this->newIncoming();
310
        } else {
311
            // TRANS: Message given submitting a form with an unknown action in e-mail settings.
312
            $this->showForm(_('Unexpected form submission.'));
313 314 315
        }
    }

316 317 318 319 320 321 322
    /**
     * Save email preferences
     *
     * @return void
     */
    function savePreferences()
    {
Siebrand Mazeland's avatar
Siebrand Mazeland committed
323
        $user = common_current_user();
324

Siebrand Mazeland's avatar
Siebrand Mazeland committed
325 326 327 328 329 330 331 332
        if (Event::handle('StartEmailSaveForm', array($this, &$user))) {
            $emailnotifysub   = $this->boolean('emailnotifysub');
            $emailnotifyfav   = $this->boolean('emailnotifyfav');
            $emailnotifymsg   = $this->boolean('emailnotifymsg');
            $emailnotifynudge = $this->boolean('emailnotifynudge');
            $emailnotifyattn  = $this->boolean('emailnotifyattn');
            $emailmicroid     = $this->boolean('emailmicroid');
            $emailpost        = $this->boolean('emailpost');
333

Siebrand Mazeland's avatar
Siebrand Mazeland committed
334
            assert(!is_null($user)); // should already be checked
335

Siebrand Mazeland's avatar
Siebrand Mazeland committed
336
            $user->query('BEGIN');
337

Siebrand Mazeland's avatar
Siebrand Mazeland committed
338
            $original = clone($user);
339

Siebrand Mazeland's avatar
Siebrand Mazeland committed
340 341 342 343 344 345 346
            $user->emailnotifysub   = $emailnotifysub;
            $user->emailnotifyfav   = $emailnotifyfav;
            $user->emailnotifymsg   = $emailnotifymsg;
            $user->emailnotifynudge = $emailnotifynudge;
            $user->emailnotifyattn  = $emailnotifyattn;
            $user->emailmicroid     = $emailmicroid;
            $user->emailpost        = $emailpost;
347

Siebrand Mazeland's avatar
Siebrand Mazeland committed
348
            $result = $user->update($original);
349

Siebrand Mazeland's avatar
Siebrand Mazeland committed
350 351 352 353 354 355
            if ($result === false) {
                common_log_db_error($user, 'UPDATE', __FILE__);
                // TRANS: Server error thrown on database error updating e-mail preferences.
                $this->serverError(_('Could not update user.'));
                return;
            }
356

Siebrand Mazeland's avatar
Siebrand Mazeland committed
357
            $user->query('COMMIT');
358

Siebrand Mazeland's avatar
Siebrand Mazeland committed
359
            Event::handle('EndEmailSaveForm', array($this));
360

Siebrand Mazeland's avatar
Siebrand Mazeland committed
361 362 363
            // TRANS: Confirmation message for successful e-mail preferences save.
            $this->showForm(_('Email preferences saved.'), true);
        }
364 365
    }

366 367 368 369 370 371 372
    /**
     * Add the address passed in by the user
     *
     * @return void
     */
    function addAddress()
    {
373 374 375 376
        $user = common_current_user();

        $email = $this->trimmed('email');

377
        // Some validation
378 379

        if (!$email) {
380
            // TRANS: Message given saving e-mail address without having provided one.
381
            $this->showForm(_('No email address.'));
382 383 384 385 386 387
            return;
        }

        $email = common_canonical_email($email);

        if (!$email) {
388
            // TRANS: Message given saving e-mail address that cannot be normalised.
389
            $this->showForm(_('Cannot normalize that email address.'));
390 391
            return;
        }
392
        if (!Validate::email($email, common_config('email', 'check_domain'))) {
393
            // TRANS: Message given saving e-mail address that not valid.
394
            $this->showForm(_('Not a valid email address.'));
395 396
            return;
        } else if ($user->email == $email) {
397
            // TRANS: Message given saving e-mail address that is already set.
398
            $this->showForm(_('That is already your email address.'));
399
            return;
400
        } else if ($this->emailExists($email)) {
401
            // TRANS: Message given saving e-mail address that is already set for another user.
402 403
            $this->showForm(_('That email address already belongs '.
                              'to another user.'));
404 405 406
            return;
        }

407
        if (Event::handle('StartAddEmailAddress', array($user, $email))) {
408

409
            $confirm = new Confirm_address();
410

411 412 413 414
            $confirm->address      = $email;
            $confirm->address_type = 'email';
            $confirm->user_id      = $user->id;
            $confirm->code         = common_confirmation_code(64);
415

416
            $result = $confirm->insert();
417

418 419 420 421 422 423 424 425 426 427 428
            if ($result === false) {
                common_log_db_error($confirm, 'INSERT', __FILE__);
                // TRANS: Server error thrown on database error adding e-mail confirmation code.
                $this->serverError(_('Could not insert confirmation code.'));
                return;
            }

            mail_confirm_address($user, $confirm->code, $user->nickname, $email);

            Event::handle('EndAddEmailAddress', array($user, $email));
        }
429

430
        // TRANS: Message given saving valid e-mail address that is to be confirmed.
431 432 433
        $msg = _('A confirmation code was sent to the email address you added. '.
                 'Check your inbox (and spam box!) for the code and instructions '.
                 'on how to use it.');
434

435
        $this->showForm($msg, true);
436 437
    }

438 439 440 441 442 443
    /**
     * Handle a request to cancel email confirmation
     *
     * @return void
     */
    function cancelConfirmation()
444
    {
445
        $email = $this->arg('email');
446 447 448

        $confirm = $this->getConfirmation();

449
        if (!$confirm) {
450
            // TRANS: Message given canceling e-mail address confirmation that is not pending.
451
            $this->showForm(_('No pending confirmation to cancel.'));
452 453 454
            return;
        }
        if ($confirm->address != $email) {
455 456
            // TRANS: Message given canceling e-mail address confirmation for the wrong e-mail address.
            $this->showForm(_('That is the wrong email address.'));
457 458
            return;
        }
459 460 461 462

        $result = $confirm->delete();

        if (!$result) {
463
            common_log_db_error($confirm, 'DELETE', __FILE__);
464
            // TRANS: Server error thrown on database error canceling e-mail address confirmation.
Siebrand Mazeland's avatar
Siebrand Mazeland committed
465
            $this->serverError(_('Could not delete email confirmation.'));
466 467 468
            return;
        }

469 470
        // TRANS: Message given after successfully canceling e-mail address confirmation.
        $this->showForm(_('Email confirmation cancelled.'), true);
471 472
    }

473 474 475 476 477 478 479
    /**
     * Handle a request to remove an address from the user's account
     *
     * @return void
     */
    function removeAddress()
    {
480
        $user = common_current_user();
481

482 483
        $email = $this->arg('email');

484
        // Maybe an old tab open...?
485 486

        if ($user->email != $email) {
487 488
            // TRANS: Message given trying to remove an e-mail address that is not
            // TRANS: registered for the active user.
489
            $this->showForm(_('That is not your email address.'));
490 491 492 493
            return;
        }

        $user->query('BEGIN');
494

495
        $original = clone($user);
496

Evan Prodromou's avatar
Evan Prodromou committed
497
        $user->email = null;
498

499
        $result = $user->updateKeys($original);
500

501 502
        if (!$result) {
            common_log_db_error($user, 'UPDATE', __FILE__);
503
            // TRANS: Server error thrown on database error removing a registered e-mail address.
Siebrand Mazeland's avatar
Siebrand Mazeland committed
504
            $this->serverError(_('Could not update user.'));
505 506 507 508
            return;
        }
        $user->query('COMMIT');

509 510
        // TRANS: Message given after successfully removing a registered e-mail address.
        $this->showForm(_('The email address was removed.'), true);
511 512
    }

513 514 515 516 517 518
    /**
     * Handle a request to remove an incoming email address
     *
     * @return void
     */
    function removeIncoming()
519
    {
520
        $user = common_current_user();
521

522
        if (!$user->incomingemail) {
523
            // TRANS: Form validation error displayed when trying to remove an incoming e-mail address while no address has been set.
524
            $this->showForm(_('No incoming email address.'));
525 526
            return;
        }
527

528
        $orig = clone($user);
529

Evan Prodromou's avatar
Evan Prodromou committed
530
        $user->incomingemail = null;
531
        $user->emailpost = 0;
532 533 534

        if (!$user->updateKeys($orig)) {
            common_log_db_error($user, 'UPDATE', __FILE__);
535
            // TRANS: Server error thrown on database error removing incoming e-mail address.
536
            $this->serverError(_('Could not update user record.'));
537
        }
538

539
        // TRANS: Message given after successfully removing an incoming e-mail address.
540
        $this->showForm(_('Incoming email address removed.'), true);
541 542
    }

543 544 545 546 547 548
    /**
     * Generate a new incoming email address
     *
     * @return void
     */
    function newIncoming()
549
    {
550
        $user = common_current_user();
551

552
        $orig = clone($user);
553

554
        $user->incomingemail = mail_new_incoming_address();
555
        $user->emailpost = 1;
556

557 558
        if (!$user->updateKeys($orig)) {
            common_log_db_error($user, 'UPDATE', __FILE__);
559
            // TRANS: Server error thrown on database error adding incoming e-mail address.
560
            $this->serverError(_('Could not update user record.'));
561 562
        }

563
        // TRANS: Message given after successfully adding an incoming e-mail address.
564
        $this->showForm(_('New incoming email address added.'), true);
565
    }
566 567 568 569 570 571 572 573 574 575 576 577

    /**
     * Does another user already have this email address?
     *
     * Email addresses are unique for users.
     *
     * @param string $email Address to check
     *
     * @return boolean Whether the email already exists.
     */

    function emailExists($email)
578
    {
579
        $user = common_current_user();
580

581
        $other = User::staticGet('email', $email);
582

583 584 585 586 587 588
        if (!$other) {
            return false;
        } else {
            return $other->id != $user->id;
        }
    }
589
}