Example #1
0
 public function value(ProfilePage $page, $field, $value, &$success)
 {
     if (is_null($value)) {
         return isset($page->values[$field]) ? $page->values[$field] : S::v($field);
     }
     $value = trim($value);
     $success = empty($value) || isvalid_email($value);
     if (!$success) {
         Platal::page()->trigError('Adresse Email invalide');
     }
     return $value;
 }
Example #2
0
 function handler_batch($page)
 {
     $page->changeTpl('carnet/batch.tpl');
     $errors = false;
     $incomplete = array();
     if (Post::has('add')) {
         S::assert_xsrf_token();
         require_once 'userset.inc.php';
         require_once 'emails.inc.php';
         require_once 'marketing.inc.php';
         $list = explode("\n", Post::v('list'));
         $origin = Post::v('origin');
         foreach ($list as $item) {
             if ($item = trim($item)) {
                 $elements = preg_split("/\\s/", $item);
                 $email = array_pop($elements);
                 if (!isvalid_email($email)) {
                     $page->trigError('Email invalide : ' . $email);
                     $incomplete[] = $item;
                     $errors = true;
                     continue;
                 }
                 $user = User::getSilent($email);
                 if (is_null($user)) {
                     $details = implode(' ', $elements);
                     $promo = trim(array_pop($elements));
                     $cond = new PFC_And();
                     if (preg_match('/^[MDX]\\d{4}$/', $promo)) {
                         $cond->addChild(new UFC_Promo('=', UserFilter::DISPLAY, $promo));
                     } else {
                         $cond->addChild(new UFC_NameTokens($promo));
                     }
                     foreach ($elements as $element) {
                         $cond->addChild(new UFC_NameTokens($element));
                     }
                     $uf = new UserFilter($cond);
                     $count = $uf->getTotalCount();
                     if ($count == 0) {
                         $page->trigError('Les informations : « ' . $item . ' » ne correspondent à aucun camarade.');
                         $incomplete[] = $item;
                         $errors = true;
                         continue;
                     } elseif ($count > 1) {
                         $page->trigError('Les informations : « ' . $item . ' » sont ambigues et correspondent à plusieurs camarades.');
                         $incomplete[] = $item;
                         $errors = true;
                         continue;
                     } else {
                         $user = $uf->getUser();
                     }
                 }
                 if ($user->state == 'active') {
                     $this->addRegistered($page, $user->profile());
                 } else {
                     if (!User::isForeignEmailAddress($email)) {
                         $page->trigError('Email pas encore attribué : ' . $email);
                         $incomplete[] = $item;
                         $errors = true;
                     } else {
                         $this->addNonRegistered($page, $user);
                         if (!Marketing::get($user->id(), $email, true)) {
                             check_email($email, "Une adresse surveillée est proposée au marketing par " . S::user()->login());
                             $market = new Marketing($user->id(), $email, 'default', null, $origin, S::v('uid'), null);
                             $market->add();
                         }
                     }
                 }
             }
         }
     }
     $page->assign('errors', $errors);
     $page->assign('incomplete', $incomplete);
 }
Example #3
0
 function handler_options($page, $liste = null)
 {
     if (is_null($liste)) {
         return PL_NOT_FOUND;
     }
     $mlist = $this->prepare_list($liste);
     if (!$this->is_group_admin($page)) {
         $this->verify_list_owner($page, $mlist);
     }
     $page->changeTpl('lists/options.tpl');
     if (Post::has('submit')) {
         S::assert_xsrf_token();
         $values = $_POST;
         $values = array_map('utf8_decode', $values);
         $spamlevel = intval($values['bogo_level']);
         $unsurelevel = intval($values['unsure_level']);
         if ($spamlevel == 0) {
             $unsurelevel = 0;
         }
         if ($spamlevel > 3 || $spamlevel < 0 || $unsurelevel < 0 || $unsurelevel > 1) {
             $page->trigError("Réglage de l'antispam non valide");
         } else {
             $mlist->setBogoLevel(($spamlevel << 1) + $unsurelevel);
         }
         switch ($values['moderate']) {
             case '0':
                 $values['generic_nonmember_action'] = 0;
                 $values['default_member_moderation'] = 0;
                 break;
             case '1':
                 $values['generic_nonmember_action'] = 1;
                 $values['default_member_moderation'] = 0;
                 break;
             case '2':
                 $values['generic_nonmember_action'] = 1;
                 $values['default_member_moderation'] = 1;
                 break;
         }
         unset($values['submit'], $values['bogo_level'], $values['moderate']);
         $values['send_goodbye_msg'] = !empty($values['send_goodbye_msg']);
         $values['admin_notify_mchanges'] = !empty($values['admin_notify_mchanges']);
         $values['subscribe_policy'] = empty($values['subscribe_policy']) ? 0 : 2;
         if (isset($values['subject_prefix'])) {
             $values['subject_prefix'] = trim($values['subject_prefix']) . ' ';
         }
         $mlist->setOwnerOptions($values);
     } elseif (isvalid_email(Post::v('atn_add'))) {
         S::assert_xsrf_token();
         $mlist->whitelistAdd(Post::v('atn_add'));
     } elseif (Get::has('atn_del')) {
         S::assert_xsrf_token();
         $mlist->whitelistRemove(Post::v('atn_del'));
         pl_redirect('lists/options/' . $liste);
     }
     if (list($details, $options) = $mlist->getOwnerOptions()) {
         $page->assign_by_ref('details', $details);
         $page->assign_by_ref('options', $options);
         $bogo_level = intval($mlist->getBogoLevel());
         $page->assign('unsure_level', $bogo_level & 1);
         $page->assign('bogo_level', $bogo_level >> 1);
     } else {
         $page->kill("La liste n'existe pas ou tu n'as pas le droit de l'administrer");
     }
 }
Example #4
0
 function handler_accounts(PlPage $page)
 {
     $page->changeTpl('admin/accounts.tpl');
     $page->setTitle('Administration - Comptes');
     if (Post::has('create_account')) {
         S::assert_xsrf_token();
         $firstname = Post::t('firstname');
         $lastname = mb_strtoupper(Post::t('lastname'));
         $sex = Post::s('sex');
         $email = Post::t('email');
         $type = Post::s('type');
         if (!$type) {
             $page->trigError("Empty account type");
         } elseif (!isvalid_email($email)) {
             $page->trigError("Invalid email address: {$email}");
         } elseif (strlen(Post::s('pwhash')) != 40) {
             $page->trigError("Invalid password hash");
         } else {
             $login = PlUser::makeHrid($firstname, $lastname, $type);
             $full_name = $firstname . ' ' . $lastname;
             $directory_name = $lastname . ' ' . $firstname;
             XDB::execute("INSERT INTO  accounts (hruid, type, state, password,\n                                                     registration_date, email, full_name,\n                                                     display_name, sex, directory_name,\n                                                     lastname, firstname)\n                                   VALUES  ({?}, {?}, 'active', {?}, NOW(), {?}, {?}, {?}, {?}, {?}, {?}, {?})", $login, $type, Post::s('pwhash'), $email, $full_name, $full_name, $sex, $directory_name, $lastname, $firstname);
         }
     }
     $uf = new UserFilter(new UFC_AccountType('ax', 'school', 'fx'));
     $page->assign('users', $uf->iterUsers());
 }
Example #5
0
 public function value(ProfilePage $page, $field, $value, &$success)
 {
     $p = Platal::page();
     $success = true;
     if (!is_null($value)) {
         $email_stripped = strtolower(trim($value));
         if (!isvalid_email($email_stripped) && $email_stripped && $page->values['email_directory'] == "*****@*****.**") {
             $p->assign('email_error', '1');
             $p->assign('email_directory_error', $email_stripped);
             $p->trigError('Adresse Email invalide');
             $success = false;
         } else {
             $p->assign('email_error', '0');
         }
     }
     return $value;
 }
Example #6
0
 /** Save the global properties of this NL issue (title&co).
  */
 public function save()
 {
     $errors = array();
     // Fill the list of fields to update
     $fields = array('title' => $this->title, 'mail_title' => $this->title_mail, 'head' => $this->head, 'signature' => $this->signature);
     if (!empty($this->reply_to) && !isvalid_email($this->reply_to)) {
         $errors[] = self::ERROR_INVALID_REPLY_TO;
     } else {
         $fields['reply_to'] = $this->reply_to;
     }
     if ($this->isEditable()) {
         $fields['date'] = $this->date;
         if (!preg_match('/^[-a-z0-9]+$/i', $this->shortname) || is_numeric($this->shortname)) {
             $errors[] = self::ERROR_INVALID_SHORTNAME;
         } else {
             $fields['short_name'] = $this->shortname;
         }
         if ($this->sufb->isValid() || $this->sufb->isEmpty()) {
             $fields['sufb_json'] = json_encode($this->sufb->export()->dict());
             // If sufb_json is too long to be store, we do not store a truncated json and notify the user.
             // The limit is LONGTEXT's one, ie 2^32 = 4294967296.
             if (strlen($fields['sufb_json']) > 4294967295) {
                 $errors[] = self::ERROR_TOO_LONG_UFC;
             }
         } else {
             $errors[] = self::ERROR_INVALID_UFC;
         }
         if ($this->nl->automaticMailingEnabled()) {
             $fields['send_before'] = $this->send_before ? $this->send_before : null;
         }
     }
     if (count($errors)) {
         return $errors;
     }
     $field_sets = array();
     foreach ($fields as $key => $value) {
         $field_sets[] = XDB::format($key . ' = {?}', $value);
     }
     XDB::execute('UPDATE  newsletter_issues
                      SET  ' . implode(', ', $field_sets) . '
                    WHERE  id={?}', $this->id);
     if (XDB::affectedRows()) {
         $this->refresh();
     } else {
         $errors[] = self::ERROR_SQL_SAVE;
     }
     return $errors;
 }
Example #7
0
 public function add_email($email)
 {
     $email_stripped = strtolower(trim($email));
     if (!isvalid_email($email_stripped)) {
         return ERROR_INVALID_EMAIL;
     }
     if (!isvalid_email_redirection($email_stripped, $this->user)) {
         return ERROR_LOOP_EMAIL;
     }
     // We first need to retrieve the value for the antispam filter: it is
     // either the user's redirections common value, or if they differ, our
     // default value.
     $bogo = new Bogo($this->user);
     $filter = $bogo->single_state ? Bogo::$states[$bogo->state] : Bogo::MAIN_DEFAULT;
     // If the email was already present for this user, we reset it to the default values, we thus use REPLACE INTO.
     XDB::execute('REPLACE INTO  email_redirect_account (uid, redirect, flags, action)
                         VALUES  ({?}, {?}, \'active\', {?})', $this->user->id(), $email, $filter);
     // Replace this email by forlife email, if present in aliases and MLs.
     $listClient = new MMList(S::user());
     $listClient->change_user_email($email, $this->user->forlifeEmail());
     update_alias_user($email, $this->user->forlifeEmail());
     if ($logger = S::v('log', null)) {
         // may be absent --> step4.php
         S::logger()->log('email_add', $email . ($this->user->id() != S::v('uid') ? " (admin on {$this->user->login()})" : ""));
     }
     foreach ($this->emails as $mail) {
         if ($mail->email == $email_stripped) {
             return SUCCESS;
         }
     }
     $this->emails[] = new Email($this->user, array('redirect' => $email, 'rewrite' => '', 'type' => 'smtp', 'action' => $filter, 'broken_date' => '0000-00-00', 'broken_level' => 0, 'last' => '0000-00-00', 'flags' => 'active', 'hash' => null, 'allow_rewrite' => 0));
     // security stuff
     check_email($email, "Ajout d'une adresse surveillée aux redirections de " . $this->user->login());
     check_redirect($this);
     $this->update_imap();
     return SUCCESS;
 }
Example #8
0
 function handler_register($page, $hash = null)
 {
     $page->forceSkin('register');
     $alert = array();
     $alert_details = '';
     $subState = new PlDict(S::v('subState', array()));
     if (!$subState->has('step')) {
         $subState->set('step', 0);
     }
     if (!$subState->has('backs')) {
         $subState->set('backs', new PlDict());
     }
     if (Get::has('back') && Get::i('back') < $subState->i('step')) {
         $subState->set('step', max(0, Get::i('back')));
         $subState->v('backs')->set($subState->v('backs')->count() + 1, $subState->dict());
         $subState->v('backs')->kill('backs');
         if ($subState->v('backs')->count() == 3) {
             $alert[] = "Tentative d'inscription très hésitante";
             $alert_details .= "\n   * Retours en arrières : 3.";
         }
     }
     if ($hash) {
         $res = XDB::query("SELECT  a.uid, a.hruid, ppn.lastname_initial AS lastname, ppn.firstname_initial AS firstname, p.xorg_id AS xorgid,\n                                       pd.promo, pe.promo_year AS yearpromo, pde.degree AS edu_type,\n                                       p.birthdate_ref AS birthdateRef, FIND_IN_SET('watch', a.flags) AS watch, m.hash, a.type, a.comment\n                                 FROM  register_marketing AS m\n                           INNER JOIN  accounts           AS a   ON (m.uid = a.uid)\n                           INNER JOIN  account_profiles   AS ap  ON (a.uid = ap.uid AND FIND_IN_SET('owner', ap.perms))\n                           INNER JOIN  profiles           AS p   ON (p.pid = ap.pid)\n                           INNER JOIN  profile_display    AS pd  ON (p.pid = pd.pid)\n                           INNER JOIN  profile_education  AS pe  ON (pe.pid = p.pid AND FIND_IN_SET('primary', pe.flags))\n                           INNER JOIN  profile_education_degree_enum AS pde ON (pde.id = pe.degreeid)\n                           INNER JOIN  profile_public_names AS ppn ON (ppn.pid = p.pid)\n                                WHERE  m.hash = {?} AND a.state = 'pending'", $hash);
         if ($res->numRows() == 1) {
             $subState->merge($res->fetchOneRow());
             $subState->set('main_mail_domain', User::$sub_mail_domains[$subState->v('type')]);
             XDB::execute('INSERT INTO  register_mstats (uid, sender, success)
                                SELECT  m.uid, m.sender, 0
                                  FROM  register_marketing AS m
                                 WHERE  m.hash
               ON DUPLICATE KEY UPDATE  sender = VALUES(sender), success = VALUES(success)', $subState->s('hash'));
         }
     }
     switch ($subState->i('step')) {
         case 0:
             $wp = new PlWikiPage('Reference.Charte');
             $wp->buildCache();
             if (Post::has('step1')) {
                 $subState->set('step', 1);
                 if ($subState->has('hash')) {
                     $subState->set('step', 3);
                     $this->load('register.inc.php');
                     createAliases($subState);
                 }
             }
             break;
         case 1:
             if (Post::has('yearpromo')) {
                 $edu_type = Post::t('edu_type');
                 $yearpromo = Post::i('yearpromo');
                 $promo = Profile::$cycle_prefixes[$edu_type] . $yearpromo;
                 $res = XDB::query("SELECT  COUNT(*)\n                                         FROM  accounts         AS a\n                                   INNER JOIN  account_profiles AS ap ON (a.uid = ap.uid AND FIND_IN_SET('owner', ap.perms))\n                                   INNER JOIN  profiles         AS p  ON (p.pid = ap.pid)\n                                   INNER JOIN  profile_education AS pe ON (pe.pid = p.pid AND FIND_IN_SET('primary', pe.flags))\n                                        WHERE  a.state = 'pending' AND p.deathdate IS NULL AND pe.promo_year = {?}", $yearpromo);
                 if (!$res->fetchOneCell()) {
                     $error = 'La promotion saisie est incorrecte ou tous les camarades de cette promotion sont inscrits !';
                 } else {
                     $subState->set('step', 2);
                     $subState->set('promo', $promo);
                     $subState->set('yearpromo', $yearpromo);
                     $subState->set('edu_type', $edu_type);
                     if ($edu_type == Profile::DEGREE_X) {
                         if ($yearpromo >= 1996 && $yearpromo < 2000) {
                             $subState->set('schoolid', $yearpromo % 100 * 10 . '???');
                             $subState->set('schoolid_exemple', $yearpromo % 100 * 10000 + 532);
                             $subState->set('schoolid_exemple_ev2', ($yearpromo + 1) % 100 * 10000 + 532);
                         } elseif ($yearpromo >= 2000) {
                             $subState->set('schoolid', 100 + $yearpromo % 100 . '???');
                             $subState->set('schoolid_exemple', (100 + $yearpromo % 100) * 1000 + 532);
                             $subState->set('schoolid_exemple_ev2', (100 + ($yearpromo + 1) % 100) * 1000 + 532);
                         }
                     }
                 }
             }
             break;
         case 2:
             if (count($_POST)) {
                 $this->load('register.inc.php');
                 $subState->set('firstname', Post::t('firstname'));
                 $subState->set('lastname', Post::t('lastname'));
                 if (Post::has('schoolid')) {
                     $subState->set('schoolid', Post::i('schoolid'));
                 }
                 $error = checkNewUser($subState);
                 if ($error !== true) {
                     break;
                 }
                 $error = createAliases($subState);
                 if ($error === true) {
                     unset($error);
                     $subState->set('step', 3);
                 }
             }
             break;
         case 3:
             if (count($_POST)) {
                 $this->load('register.inc.php');
                 // Validate the email address format and domain.
                 require_once 'emails.inc.php';
                 $user = User::get($subState->s('uid'));
                 if (!isvalid_email(Post::v('email'))) {
                     $error[] = "Le champ 'Email' n'est pas valide.";
                 } elseif (!isvalid_email_redirection(Post::v('email'), $user)) {
                     $error[] = $subState->s('forlife') . ' doit renvoyer vers un email existant ' . 'valide, en particulier, il ne peut pas être renvoyé vers lui-même.';
                 }
                 // Validate the birthday format and range.
                 $birth = Post::t('birthdate');
                 if (!preg_match('@^[0-3]?\\d/[01]?\\d/(19|20)?\\d{2}$@', $birth)) {
                     $error[] = "La 'Date de naissance' n'est pas correcte.";
                 } else {
                     $birth = explode('/', $birth, 3);
                     for ($i = 0; $i < 3; ++$i) {
                         $birth[$i] = intval($birth[$i]);
                     }
                     if ($birth[2] < 100) {
                         $birth[2] += 1900;
                     }
                     $year = $birth[2];
                     $ref_year = substr($subState->v('birthdateRef'), 0, 4);
                     if (abs($ref_year - $year) > 2) {
                         $error[] = "La 'Date de naissance' n'est pas correcte.";
                         $alert[] = "Date de naissance incorrecte à l'inscription";
                         $alert_details .= "\n   * Date de naissance renseignée : " . Post::t('birthdate');
                         if ($subState->v('birthdateRef') == '0000-00-00') {
                             $alert_details .= ' (date inconnue)';
                         } else {
                             $alert_details .= ' (date connue : ' . $subState->v('birthdateRef') . ')';
                         }
                         $subState->set('wrong_birthdate', $birth);
                     }
                 }
                 // Register the optional services requested by the user.
                 $services = array();
                 foreach (array('com_letters', 'imap', 'ml_promo', 'nl') as $service) {
                     if (Post::b($service)) {
                         $services[] = $service;
                     }
                 }
                 $subState->set('services', $services);
                 // Validate the password.
                 if (!Post::v('pwhash', false)) {
                     $error[] = "Le mot de passe n'est pas valide.";
                 }
                 // Check if the given email is known as dangerous.
                 $res = XDB::query("SELECT  state, description\n                                         FROM  email_watch\n                                        WHERE  email = {?} AND state != 'safe'", Post::v('email'));
                 $bannedEmail = false;
                 if ($res->numRows()) {
                     list($state, $description) = $res->fetchOneRow();
                     $alert[] = "Email surveillé proposé à l'inscription";
                     $alert_details .= "\n   * Email surveillé : " . Post::v('email');
                     $subState->set('email_desc', $description);
                     if ($state == 'dangerous') {
                         $bannedEmail = true;
                     }
                 }
                 if ($subState->i('watch') != 0) {
                     $alert[] = "Inscription d'un utilisateur surveillé";
                     $alert_details .= "\n   * Commentaire pour la surveillance : " . $subState->v('comment');
                 }
                 if ($bannedIp = check_ip('unsafe')) {
                     unset($error);
                 }
                 if (isset($error)) {
                     $error = join('<br />', $error);
                 } else {
                     $subState->set('birthdate', sprintf("%04d-%02d-%02d", intval($birth[2]), intval($birth[1]), intval($birth[0])));
                     $subState->set('email', Post::t('email'));
                     $subState->set('password', Post::t('pwhash'));
                     // Update the current alert if the birthdate is incorrect,
                     // or if the IP address of the user has been banned.
                     if ($subState->s('birthdateRef') != '0000-00-00' && $subState->s('birthdateRef') != $subState->s('birthdate')) {
                         $alert[] = "Date de naissance incorrecte à l'inscription";
                         $alert_details .= "\n   * Date de naissance renseignée : " . Post::t('birthdate');
                         if ($subState->v('birthdateRef') == '0000-00-00') {
                             $alert_details .= ' (date inconnue)';
                         } else {
                             $alert_details .= ' (date connue : ' . $subState->v('birthdateRef') . ')';
                         }
                     }
                     if ($bannedIp) {
                         $alert[] = "Tentative d'inscription depuis une IP surveillée";
                         $alert_details .= "\n   * IP surveillée : " . $_SESSION['check_ip'];
                     }
                     // Prevent banned user from actually registering; save the current state for others.
                     if ($bannedEmail || $bannedIp) {
                         global $globals;
                         $error = "Une erreur s'est produite lors de l'inscription." . " Merci de contacter <a href='mailto:register@{$globals->mail->domain}>" . " register@{$globals->mail->domain}</a>" . " pour nous faire part de cette erreur.";
                     } else {
                         $subState->set('step', 4);
                         if ($subState->v('backs')->count() >= 3) {
                             $alert[] = "Fin d'une inscription hésitante";
                             $alert_details .= "\n   * Nombre de retours en arrière : " . $subState->v('backs')->count();
                         }
                         finishRegistration($subState);
                     }
                 }
             }
             break;
     }
     $_SESSION['subState'] = $subState->dict();
     if (count($alert)) {
         $alert_details = "Détails des alertes :" . $alert_details . "\n\n";
         $alert_details .= 'Compte concerné : ' . $subState->s('forlife') . ' (redirection vers : ' . ($subState->s('email') == '' ? Post::t('email') : $subState->s('email')) . ")\n\n\n";
         send_warning_mail(implode(' - ', $alert), $alert_details);
     }
     $page->changeTpl('register/step' . $subState->i('step') . '.tpl');
     if (isset($error)) {
         $page->trigError($error);
     }
 }
Example #9
0
 public static function getBulkForlifeEmailsFromEmail($emails)
 {
     if (!is_array($emails)) {
         if (strlen(trim($emails)) == 0) {
             return null;
         }
         $emails = preg_split("/[; ,\r\n\\|]+/", $emails);
     }
     if ($emails) {
         $list = array();
         foreach ($emails as $i => $email) {
             $email = trim($email);
             if (empty($email)) {
                 continue;
             }
             if ($user = User::getUserFromEmail($email)) {
                 $list[$i] = $user->forlifeEmail();
             } else {
                 if (User::isForeignEmailAddress($email) && isvalid_email($email)) {
                     $list[$i] = $email;
                 }
             }
         }
         return array_unique($list);
     }
     return null;
 }
Example #10
0
 function handler_admin_member_new($page, $email = null)
 {
     global $globals;
     $page->changeTpl('xnetgrp/membres-add.tpl');
     $page->addJsLink('xnet_members.js');
     if (is_null($email)) {
         return;
     }
     S::assert_xsrf_token();
     $suggest_account_activation = false;
     // FS#703 : $_GET is urldecoded twice, hence
     // + (the data) => %2B (in the url) => + (first decoding) => ' ' (second decoding)
     // Since there can be no spaces in emails, we can fix this with :
     $email = str_replace(' ', '+', $email);
     $is_valid_email = isvalid_email($email);
     // X not registered to main site.
     if (Env::v('x') && Env::i('userid') && $is_valid_email) {
         $user = User::getSilentWithUID(Env::i('userid'));
         if (!$user) {
             $page->trigError('Utilisateur invalide.');
             return;
         }
         // User has an account but is not yet registered.
         if ($user->state == 'pending') {
             // Add email in account table.
             XDB::query('UPDATE  accounts
                            SET  email = {?}
                          WHERE  uid = {?} AND email IS NULL', $email, $user->id());
             // Add email for marketing if required.
             if (Env::v('marketing')) {
                 $market = Marketing::get($user->uid, $email);
                 if (!$market) {
                     $market = new Marketing($user->uid, $email, 'group', $globals->asso('nom'), Env::v('marketing_from'), S::v('uid'));
                     $market->add();
                 }
             }
         } elseif (Env::v('broken')) {
             // Add email for broken if required.
             $valid = new BrokenReq(S::user(), $user, $email, 'Groupe : ' . $globals->asso('nom'));
             $valid->submit();
         }
     } else {
         $user = User::getSilent($email);
         // Wrong email and no user: failure.
         if (is_null($user) && (!$is_valid_email || !User::isForeignEmailAddress($email))) {
             $page->trigError('«&nbsp;<strong>' . $email . '</strong>&nbsp;» n\'est pas une adresse email valide.');
             return;
         }
         // Deals with xnet accounts.
         if (is_null($user) || $user->type == 'xnet') {
             // User is of type xnet. There are 3 possible cases:
             //  * the email is not known yet: we create a new account and
             //      propose to send an email to the user so he can activate
             //      his account,
             //  * the email is known but the user was not contacted in order to
             //      activate yet: we propose to send an email to the user so he
             //      can activate his account,
             //  * the email is known and the user was already contacted or has
             //      an active account: nothing to be done.
             list($mbox, $domain) = explode('@', strtolower($email));
             $hruid = User::makeHrid($mbox, $domain, 'ext');
             // User might already have an account (in another group for example).
             $user = User::getSilent($hruid);
             // If the user has no account yet, creates new account: build names from email address.
             if (empty($user)) {
                 require_once 'name.func.inc.php';
                 $parts = explode('.', $mbox);
                 if (count($parts) == 1) {
                     $lastname = $display_name = capitalize_name($mbox);
                     $firstname = '';
                 } else {
                     $display_name = $firstname = capitalize_name($parts[0]);
                     $lastname = capitalize_name(implode(' ', array_slice($parts, 1)));
                 }
                 $full_name = build_full_name($firstname, $lastname);
                 $directory_name = build_directory_name($firstname, $lastname);
                 $sort_name = build_sort_name($firstname, $lastname);
                 XDB::execute('INSERT INTO  accounts (hruid, display_name, full_name, directory_name, sort_name,
                                                      firstname, lastname, email, type, state)
                                    VALUES  ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, \'xnet\', \'disabled\')', $hruid, $display_name, $full_name, $directory_name, $sort_name, $firstname, $lastname, $email);
                 $user = User::getSilent($hruid);
             }
             $suggest_account_activation = $this->suggest($user);
         }
     }
     if ($user) {
         // First check if the user used to be in this group.
         XDB::rawExecute('DELETE FROM  group_former_members
                                WHERE  remember AND DATE_SUB(NOW(), INTERVAL 1 YEAR) > unsubsciption_date');
         $former_member = XDB::fetchOneCell('SELECT  remember
                                               FROM  group_former_members
                                              WHERE  uid = {?} AND asso_id = {?}', $user->id(), $globals->asso('id'));
         if ($former_member === 1) {
             $page->trigError($user->fullName() . ' est un ancien membre du groupe qui ne souhaite pas y revenir. S\'il souhaite revenir dans le groupe, il faut qu\'il en fasse la demande sur la page d\'accueil du groupe.');
             return;
         } elseif (!is_null($former_member) && Post::i('force_continue') == 0) {
             $page->trigWarning($user->fullName() . ' est un ancien membre du groupe qui s\'est récemment désinscrit. Malgré cela, si tu penses qu\'il souhaite revenir, cliquer sur « Ajouter » l\'ajoutera bien au groupe cette fois.');
             $page->assign('force_continue', 1);
             return;
         }
         Group::subscribe($globals->asso('id'), $user->id());
         $this->removeSubscriptionRequest($user->id());
         if ($user->isActive() && $user->bestEmail()) {
             $mailer = new PlMailer('xnetgrp/forced-subscription.mail.tpl');
             $mailer->addTo($user->bestEmail());
             $mailer->assign('group', $globals->asso('nom'));
             $mailer->assign('anim', S::user()->fullname());
             $mailer->assign('diminutif', $globals->asso('diminutif'));
             $mailer->send();
         }
         // Check if the group has more than 1000 members, if so, disable the "send mail" function.
         $full_count = XDB::fetchOneCell('SELECT COUNT(*)
                                            FROM group_members
                                           WHERE asso_id = {?}', $globals->asso('id'));
         if ($full_count > 999) {
             XDB::execute("UPDATE groups\n                    SET disable_mails = 1\n                    WHERE id = {?}", $globals->asso('id'));
         }
         if ($suggest_account_activation) {
             pl_redirect('member/suggest/' . $user->login() . '/' . $email . '/' . $globals->asso('nom'));
         } else {
             pl_redirect('member/' . $user->login());
         }
     }
 }