Merge commit 'origin/master' into fusionax
authorStéphane Jacob <sj@m4x.org>
Fri, 13 Nov 2009 19:24:01 +0000 (20:24 +0100)
committerStéphane Jacob <sj@m4x.org>
Fri, 13 Nov 2009 19:24:01 +0000 (20:24 +0100)
17 files changed:
1  2 
ChangeLog
bin/cron/checkdb.php
classes/xnetpage.php
configs/platal.ini
include/notifs.inc.php
include/user.func.inc.php
include/userset.inc.php
modules/admin.php
modules/email.php
modules/events.php
modules/newsletter.php
modules/profile.php
modules/register.php
modules/search.php
modules/search/classes.inc.php
modules/search/search.inc.php
templates/survey/show_root.tpl

diff --combined ChangeLog
+++ b/ChangeLog
@@@ -1,23 -1,10 +1,28 @@@
  ================================================================================
- VERSION 0.10.2                                                        XX XX XXXX
 +VERSION 0.f.0                                                         XX XX XXXX
 +
 +New:
 +    * Core:
 +        - Centralises email management through an email combobox           -JAC
 +
 +Bug/Wish:
 +    * Profile:
 +        - #16, #528, #917: Changes job interface, updates business sectors -JAC
 +        - #188: Adds informations about the Corps d'État                   -JAC
 +        - #209: Thoroughly changes education's implementation              -JAC
 +        - #373: User now chooses the name we use to talk to him/her        -JAC
 +        - #386: Adds the possibility to fill in multiple nationalities     -JAC
 +        - #443: Adds concept of ordinary firstname                         -JAC
 +        - #450: Adds marital name, thus ordinary name can be any name      -JAC
 +        - #891: Improves education display                                 -JAC
 +
 +================================================================================
+ VERSION 0.10.3                                                        XX XX XXXX
+ New:
+ ================================================================================
+ VERSION 0.10.2                                                        13 11 2009
  
  New:
  
@@@ -26,6 -13,7 +31,7 @@@
  
      * Core:
          - Prunes old sessions/events logs after 12 months                  -VZA
+         - Adds proper content caching for static and semi-static content   -VZA
  
  Bug/Wish:
  
@@@ -34,6 -22,7 +40,7 @@@
  
      * Carnet:
          - #975: Cleans up watch_nonins when someone dies                   -JAC
+         - #1000: Notifies her contacts when a user has no redirection left -JAC
  
      * Core:
          - #984: Properly upper/lowercases accented letters when necessary  -JAC
@@@ -1419,9 -1408,7 +1426,9 @@@ ACRONYMS
      * CAT: Florian El Ahdab     (LeChat)    <florian.el-ahdab@m4x.org>
      * FAL: Raphaël Marichez     (Falco)     <raphael.marichez@m4x.org>
      * FRU: Florent Bruneau      (Fruneau)   <florent.bruneau@m4x.org>
 +    * GUI: Guillaume Bandet     (GUI)       <guillaume.bandet@m4x.org>
      * JAC: Stéphane Jacob       (jacou)     <stephane.jacob@m4x.org>
 +    * JM : Jean-Marc Bécu                   <jean-marc.becu@m4x.org>
      * JS : Jean Sébastien Bedo              <jean-sebastien.bedo@m4x.org>
      * MC : Pierre Habouzit      (MadCoder)  <pierre.habouzit@m4x.org>
      * mYk: Aymeric Augustin     (mYk)       <aymeric.augustin@m4x.org>
diff --combined bin/cron/checkdb.php
@@@ -73,19 -73,17 +73,19 @@@ if ( PEAR::isError($opts) ) 
  
  /* Validite des flags de transmission */
  check("SELECT  u.user_id, nom, prenom, promo,
 -               profile_mobile_pub, emails_alias_pub, profile_web_pub, profile_freetext_pub, profile_medals_pub
 +               emails_alias_pub, profile_freetext_pub, profile_medals_pub
           FROM  auth_user_md5 AS u
     INNER JOIN  auth_user_quick AS q USING(user_id)
 -        WHERE  (profile_mobile_pub != 'private' AND profile_mobile_pub != 'ax' AND profile_mobile_pub != 'public')
 -           OR  (emails_alias_pub != 'private' AND emails_alias_pub != 'public')
 -           OR  (profile_web_pub != 'private' AND profile_web_pub != 'public')
 +        WHERE  (emails_alias_pub != 'private' AND emails_alias_pub != 'public')
             OR  (profile_freetext_pub != 'private' AND profile_freetext_pub != 'public')
             OR  (profile_medals_pub != 'private' AND profile_medals_pub != 'public')",
      "Utilisateur n'ayant pas de flag de publicite pour leurs donnees de profil");
 -check("select uid from adresses where pub != 'private' and pub !='ax' and pub != 'public'", "Utiliseur n'ayant pas de flag de publicite pour une adresse");
 -check("select uid from tels where tel_pub != 'private' and tel_pub !='ax' and tel_pub != 'public'", "Utiliseur n'ayant pas de flag de publicite pour un numero de telephone");
 +check("SELECT  pid
 +         FROM  profile_addresses
 +        WHERE  pub != 'private' AND pub !='ax' AND pub != 'public'",
 +      "Utiliseur n'ayant pas de flag de publicité pour une adresse.");
 +check("select uid from profile_phones where pub != 'private' and pub != 'ax' and pub != 'public'", "Utiliseur n'ayant pas de flag de publicite pour un numero de téléphone");
 +check("select uid from profile_networking where pub != 'private' and pub != 'public'", "Utiliseur n'ayant pas de flag de publicité pour une adresse de networking");
  
  /* validite des hruid */
  check("SELECT user_id, nom, prenom, promo FROM auth_user_md5 WHERE hruid IS NULL OR hruid = ''",
@@@ -97,9 -95,9 +97,9 @@@ check("SELECT a.
          LEFT JOIN auth_user_md5 AS u ON u.user_id=a.id
          WHERE (a.type='alias' OR a.type='a_vie') AND u.prenom is null");
  
 -/* validite de applis_ins */
 -check("select a.* from applis_ins as a left join auth_user_md5 as u on u.user_id=a.uid where u.prenom is null");
 -check("select a.* from applis_ins as a left join applis_def as ad on ad.id=a.aid where ad.text is null");
 +/* validite de profile_education */
 +check("select a.* from profile_education as a left join auth_user_md5 as u on u.user_id=a.uid where u.prenom is null");
 +check("select a.* from profile_education as a left join profile_education_enum as ad on ad.id=a.eduid where ad.name is null");
  
  /* validite de binet_users */
  check("select b.* from binets_ins as b left join auth_user_md5 as u on u.user_id=b.user_id where u.prenom is null");
@@@ -113,10 -111,10 +113,10 @@@ check("select c.* from contacts as c le
  check("select e.* from emails as e left join auth_user_md5 as u on u.user_id=e.uid where e.uid and u.prenom is null");
  
  /* validite de forums */
- check("select f.* from forums.abos as f left join auth_user_md5 as u on u.user_id=f.uid where u.prenom is null");
- check("select f.* from forums.abos as f left join forums.list as fd on fd.fid=f.fid where fd.nom is null");
- check("select f.* from forums.respofaqs as f left join forums.list as fd on fd.fid=f.fid where fd.nom is null");
- check("select f.* from forums.respofaqs as f left join auth_user_md5 as u on u.user_id=f.uid where u.prenom is null");
+ check("select f.* from #forums#.abos as f left join #x4dat#.auth_user_md5 as u on u.user_id=f.uid where u.prenom is null");
+ check("select f.* from #forums#.abos as f left join #forums#.list as fd on fd.fid=f.fid where fd.nom is null");
+ check("select f.* from #forums#.respofaqs as f left join #forums#.list as fd on fd.fid=f.fid where fd.nom is null");
+ check("select f.* from #forums#.respofaqs as f left join #x4dat#.auth_user_md5 as u on u.user_id=f.uid where u.prenom is null");
  
  /* validite de groupesx_ins */
  check("select g.* from groupesx_ins as g left join auth_user_md5 as u on u.user_id=g.guid where u.prenom is null");
@@@ -125,24 -123,10 +125,24 @@@ check("select g.* from groupesx_ins as 
  /* validite de photo */
  check("select p.* from photo as p left join auth_user_md5 as u on u.user_id=p.uid where u.prenom is null");
  
 -/* validite des champ pays et region */
 -check("SELECT a.uid, a.country FROM adresses AS a LEFT JOIN geoloc_pays AS gp ON a.country = gp.a2 WHERE gp.pays IS NULL","donne la liste des pays dans les profils qui n'ont pas d'entree correspondante dans geoloc_pays");
 -/* les régions ne sont valides que dans les adresses pros */
 -//check("SELECT e.uid, e.country, e.region FROM entreprises AS e LEFT JOIN geoloc_region AS gr ON (e.country = gr.a2 AND e.region = gr.region) WHERE e.region != '' AND gr.name IS NULL","donne la liste des regions dans les profils pros qui n'ont pas d'entree correspondante dans geoloc_region");
 +/* validite des formats téléphoniques */
 +check("SELECT DISTINCT  g.phonePrefix
 +                  FROM  geoloc_countries AS g
 +          WHERE EXISTS  (SELECT  h.phonePrefix
 +                           FROM  geoloc_countries AS h
 +                          WHERE  h.phonePrefix = g.phonePrefix
 +                                 AND h.phoneFormat != (SELECT  i.phoneFormat
 +                                                         FROM  geoloc_countries AS i
 +                                                        WHERE  i.phonePrefix = g.phonePrefix
 +                                                        LIMIT  1))",
 +      "Préfixes téléphoniques qui ont des formats de numéros de téléphones différents selon les pays");
 +
 +/* validite des champ pays */
 +check("SELECT  a.pid, a.countryId
 +         FROM  profile_addresses AS a
 +    LEFT JOIN  geoloc_countries  AS gc ON (a.countryId = gc.iso_3166_1_a2)
 +        WHERE  gc.countryFR IS NULL OR gc.countryFR = ''",
 +      "donne la liste des pays dans les profils qui n'ont pas d'entree correspondante dans geoloc_countries");
  
  /* donne la liste des emails douteux que les administrateurs n'ont pas encore traité */
  check("SELECT  a1.alias, a2.alias, e1.email, e2.flags
@@@ -196,12 -180,6 +196,12 @@@ check("SELECT  matricule,nom,prenom,mat
          GROUP BY  matricule_ax
          having  c > 1", "à chaque personne de l'annuaire de l'AX (identification_ax) doit correspondre AU PLUS UNE personne de notre annuaire (auth_user_md5) -> si ce n'est pas le cas il faut regarder en manuel ce qui ne va pas !");
  
 +/* no alumni is allowed to have empty names */
 +check("SELECT  s.uid, d.public_name
 +         FROM  profile_name    AS s
 +   INNER JOIN  profile_display AS d ON (d.pid = s.uid)
 +        WHERE  name = ''", "liste des personnes qui ont un de leur nom de recherche vide");
 +
  /* verifie qu'il n'y a pas d'utilisateurs ayant un compte Google Apps désactivé et une redirection encore active vers Google Apps */
  check("SELECT  a.alias, g.g_status, u.mail_storage
           FROM  auth_user_md5 AS u
diff --combined classes/xnetpage.php
@@@ -41,6 -41,9 +41,9 @@@ class XnetPage extends PlPag
              $this->assign('is_admin', may_update());
              $this->assign('is_member', is_member());
          }
+         $this->addJsLink('jquery.js');
+         $this->addJsLink('overlib.js');
+         $this->addJsLink('wiki.js');
          $this->addJsLink('xorg.js');
          $this->setTitle('Les associations polytechniciennes');
      }
@@@ -87,6 -90,7 +90,6 @@@
              if ($perms->hasFlag('groupannu')) {
                  $sub['annuaire du groupe'] = "$dim/annuaire";
                  $sub['trombinoscope'] = "$dim/trombi";
 -                $sub['planisphère'] = "$dim/geoloc";
              }
              if ($perms->hasFlag('groupmember')) {
                  if ($globals->asso('forum')) {
@@@ -140,8 -144,8 +143,8 @@@ function list_all_my_groups($params
      }
      $res = XDB::iterRow(
              "SELECT  a.nom, a.diminutif
-                FROM  groupex.asso    AS a
-          INNER JOIN  groupex.membres AS m ON m.asso_id = a.id
+                FROM  #groupex#.asso    AS a
+          INNER JOIN  #groupex#.membres AS m ON m.asso_id = a.id
                WHERE  m.uid={?}", S::v('uid'));
      $links = '<a href="exit">déconnexion</a>';
      $html = '<div>Mes groupes (' . $links . ') :</div>';
diff --combined configs/platal.ini
@@@ -24,10 -24,8 +24,10 @@@ mbox_helper  = "/usr/bin/banana-mbox-he
  event_forum = ""
  event_reply = ""
  
 -[Geoloc]
 -webservice_url = ""
 +[Geocoder]
 +email = ""
 +gmaps_key = ""
 +gmaps_url = "http://maps.google.com/maps/geo"
  
  [Lists]
  rpchost   = "localhost"
@@@ -47,6 -45,7 +47,7 @@@ alias_dom2 = "
  
  blacklist_check_url = ""
  blacklist_host_resolution_limit =
+ domain_whitelist = ""
  
  [MailStorage]
  imap_active = 0
diff --combined include/notifs.inc.php
@@@ -146,23 -146,22 +146,24 @@@ function select_notifs($mail, $uid=null
  // {{{
  
  global $prf_desc;
 -$prf_desc = array('nom'         => 'Son patronyme',
 -                  'freetext'    => 'Le texte libre',
 -                  'mobile'      => 'Son numéro de téléphone portable',
 -                  'nationalite' => 'Sa nationalité',
 -                  'nick'        => 'Son surnom',
 -                  'web'         => "L'adresse de son site web",
 -                  'appli1'      => "Son école d'application",
 -                  'appli2'      => 'Son école de post-application',
 -                  'addresses'   => 'Ses adresses',
 -                  'section'     => 'Sa section sportive',
 -                  'binets'      => 'La liste de ses binets',
 -                  'medals'      => 'Ses décorations',
 -                  'cv'          => 'Son curriculum vitae',
 -                  'jobs'        => 'Ses informations professionnelles',
 -                  'photo'       => 'Sa photographie',
 +$prf_desc = array('search_names' => 'L\'un de ses noms',
-                   'freetext' => 'Le texte libre',
-                   'mobile' => 'Son numéro de téléphone portable',
-                   'nationalite' => 'Sa nationalité',
++                  'freetext'     => 'Le texte libre',
++                  'mobile'       => 'Son numéro de téléphone portable',
++                  'nationalite'  => 'Sa nationalité',
 +                  'nationalite2' => 'Sa seconde nationalité',
 +                  'nationalite3' => 'Sa troisième nationalité',
-                   'nick' => 'Son surnom',
-                   'networking' => 'La liste de ses adresses de networking',
-                   'edus' => 'Ses formations',
-                   'addresses' => 'Ses adresses',
-                   'section' => 'Sa section sportive',
-                   'binets' => 'La liste de ses binets',
-                   'medals' => 'Ses décorations',
-                   'cv' => 'Son Curriculum Vitae',
-                   'corps' => 'Son Corps d\'État',
-                   'jobs' => 'Ses informations professionnelles',
-                   'photo' => 'Sa photographie');
++                  'nick'         => 'Son surnom',
++                  'networking'   => 'La liste de ses adresses de networking',
++                  'edus'         => 'Ses formations',
++                  'addresses'    => 'Ses adresses',
++                  'section'      => 'Sa section sportive',
++                  'binets'       => 'La liste de ses binets',
++                  'medals'       => 'Ses décorations',
++                  'cv'           => 'Son Curriculum Vitae',
++                  'corps'        => 'Son Corps d\'État',
++                  'jobs'         => 'Ses informations professionnelles',
++                  'photo'        => 'Sa photographie',
+                   'broken'      => "Il n'a plus d'adresse de redirection valide");
  
  function get_profile_change_details($event, $limit) {
      global $prf_desc;
@@@ -26,7 -26,7 +26,7 @@@
   */
  function user_clear_all_subs($user_id, $really_del=true)
  {
 -    // keep datas in : aliases, adresses, tels, applis_ins, binets_ins, contacts, groupesx_ins, homonymes, identification_ax, photo
 +    // keep datas in : aliases, adresses, tels, profile_education, binets_ins, contacts, groupesx_ins, homonymes, identification_ax, photo
      // delete in     : auth_user_md5, auth_user_quick, competences_ins, emails, entreprises, langues_ins, mentor,
      //                 mentor_pays, mentor_secteurs, newsletter_ins, perte_pass, requests, user_changes, virtual_redirect, watch_sub
      // + delete maillists
      $user = User::getSilent($uid);
      list($alias) = explode('@', $user->forlifeEmail());
  
 -    $tables_to_clear = array('uid' => array('competences_ins', 'entreprises', 'langues_ins', 'mentor_pays',
 -                                            'mentor_secteurs', 'mentor', 'perte_pass', 'watch_sub'),
 +    $tables_to_clear = array('uid' => array('competences_ins', 'profile_job', 'langues_ins', 'profile_mentor_country',
 +                                            'profile_mentor_sector', 'profile_mentor', 'perte_pass', 'watch_sub'),
                               'user_id' => array('requests', 'user_changes'));
  
      if ($really_del) {
-         array_push($tables_to_clear['uid'], 'emails', 'groupex.membres', 'contacts', 'adresses', 'profile_phones',
-                                             'photo', 'perte_pass', 'langues_ins', 'forums.abos', 'forums.profils');
 -        array_push($tables_to_clear['uid'], 'emails', '#groupex#.membres', 'contacts', 'adresses', 'tels',
 -                                            'photo', 'perte_pass', 'langues_ins', '#forums#.abos', '#forums#.profils');
++        array_push($tables_to_clear['uid'], 'emails', '#groupex#.membres', 'contacts', 'adresses', 'profile_phones',
++                                            'photo', 'perte_pass', 'langues_ins', '#forums#.abos', 'forums.profils');
          array_push($tables_to_clear['user_id'], 'newsletter_ins', 'auth_user_quick', 'binets_ins');
          $tables_to_clear['id'] = array('aliases');
          $tables_to_clear['contact'] = array('contacts');
          XDB::execute("UPDATE auth_user_md5
                           SET date_ins = 0, promo_sortie = 0, nom_usage = '',  password = '', perms = 'pending',
 -                             nationalite = '', cv = '', section = 0, date = 0, smtppass = '', mail_storage = ''
 +                             nationalite = '', nationalite2 = '', nationalite3 = '', cv = '', section = 0,
 +                             date = 0, smtppass = '', mail_storage = ''
                         WHERE user_id = {?}", $uid);
          XDB::execute("DELETE virtual.* FROM virtual INNER JOIN virtual_redirect AS r USING(vid) WHERE redirect = {?}",
                       $alias.'@'.$globals->mail->domain);
@@@ -132,19 -131,18 +132,19 @@@ function get_not_registered_user($login
  
  function get_user_details_pro($uid, $view = 'private')
  {
 -    $sql  = "SELECT  e.entreprise, s.label as secteur , ss.label as sous_secteur , f.fonction_fr as fonction,
 -                     e.poste, e.adr1, e.adr2, e.adr3, e.postcode, e.city, e.entrid,
 -                     gp.pays AS countrytxt, gr.name AS region, e.tel, e.fax, e.mobile, e.entrid,
 -                     e.pub, e.adr_pub, e.tel_pub, e.email, e.email_pub, e.web
 -               FROM  entreprises AS e
 -          LEFT JOIN  emploi_secteur AS s ON(e.secteur = s.id)
 -          LEFT JOIN  emploi_ss_secteur AS ss ON(e.ss_secteur = ss.id AND e.secteur = ss.secteur)
 -          LEFT JOIN  fonctions_def AS f ON(e.fonction = f.id)
 -          LEFT JOIN  geoloc_pays AS gp ON (gp.a2 = e.country)
 -          LEFT JOIN  geoloc_region AS gr ON (gr.a2 = e.country and gr.region = e.region)
 -              WHERE  e.uid = {?}
 -           ORDER BY  e.entrid";
 +    $sql  = "SELECT  en.name AS entreprise, s.name as secteur, f.fonction_fr as fonction,
 +                     j.description AS poste, gp.pays AS countrytxt, gr.name AS region,
 +                     j.id AS entrid, j.pub, j.email, j.email_pub, j.url AS w_web, en.url AS web,
 +                     e.adr1, e.adr2, e.adr3, e.postcode, e.city, e.adr_pub
 +               FROM  profile_job                   AS j
 +          LEFT JOIN  entreprises                   AS e  ON (e.entrid = j.id AND e.uid = j.uid)
 +          LEFT JOIN  profile_job_enum              AS en ON (j.jobid = en.id)
 +          LEFT JOIN  profile_job_subsubsector_enum AS s  ON (j.subsubsectorid = s.id)
 +          LEFT JOIN  fonctions_def                 AS f  ON (j.functionid = f.id)
 +          LEFT JOIN  geoloc_pays                   AS gp ON (gp.a2 = e.country)
 +          LEFT JOIN  geoloc_region                 AS gr ON (gr.a2 = e.country AND gr.region = e.region)
 +              WHERE  j.uid = {?}
 +           ORDER BY  j.id";
      $res  = XDB::query($sql, $uid);
      $all_pro = $res->fetchAllAssoc();
      foreach ($all_pro as $i => $pro) {
                      $all_pro[$i]['region'] = '';
                  }
              }
 -            if (!has_user_right($pro['tel_pub'], $view)) {
 -                // if no tel was defined, then the viewer will be able to write it
 -                if ($pro['tel'] == '' &&
 -                    $pro['fax'] == '' &&
 -                    $pro['mobile'] == '') {
 -                    $all_pro[$i]['tel_pub'] = $view;
 -                } else {
 -                    $all_pro[$i]['tel'] = '';
 -                    $all_pro[$i]['fax'] = '';
 -                    $all_pro[$i]['mobile'] = '';
 +            $sql = "SELECT  pub AS tel_pub, tel_type, display_tel AS tel, comment
 +                      FROM  profile_phones AS t
 +                     WHERE  uid = {?} AND link_type = 'pro' AND link_id = {?}
 +                  ORDER BY  link_id, tel_type DESC, tel_id";
 +            $restel = XDB::iterator($sql, $uid, $pro['entrid']);
 +            while ($nexttel = $restel->next()) {
 +                if (has_user_right($nexttel['tel_pub'], $view)) {
 +                    if (!isset($all_pro[$i]['tels'])) {
 +                        $all_pro[$i]['tels'] = array($nexttel);
 +                    } else {
 +                        $all_pro[$i]['tels'][] = $nexttel;
 +                    }
                  }
              }
              if (!has_user_right($pro['email_pub'], $view)) {
                  $all_pro[$i]['fonction'] == '' &&
                  $all_pro[$i]['secteur'] == '' &&
                  $all_pro[$i]['poste'] == '' &&
 -                $all_pro[$i]['tel'] == '' &&
 -                $all_pro[$i]['fax'] == '' &&
 -                $all_pro[$i]['mobile'] == '' &&
 +                (!isset($all_pro[$i]['tels'])) &&
                  $all_pro[$i]['email'] == '')
                  unset($all_pro[$i]);
          }
@@@ -219,7 -217,7 +219,7 @@@ function get_user_details_adr($uid, $vi
                       FIND_IN_SET('active', a.statut) AS active, a.adrid,
                       FIND_IN_SET('res-secondaire', a.statut) AS secondaire,
                       FIND_IN_SET('courrier', a.statut) AS courier,
 -                     a.pub, gp.display
 +                     a.pub, gp.display, a.comment
                 FROM  adresses AS a
            LEFT JOIN  geoloc_pays AS gp ON (gp.a2=a.country)
                WHERE  uid= {?} AND NOT FIND_IN_SET('pro',a.statut)
              $adrid_index[$adr['adrid']] = $i;
      }
  
 -    $sql = "SELECT  t.adrid, t.tel_pub, t.tel_type, t.tel, t.telid
 -              FROM  tels AS t
 -        INNER JOIN  adresses AS a ON (a.uid = t.uid) AND (a.adrid = t.adrid)
 -             WHERE  t.uid = {?} AND NOT FIND_IN_SET('pro',a.statut)
 -          ORDER BY  t.adrid, t.tel_type DESC, t.telid";
 +    $sql = "SELECT  link_id AS adrid, pub AS tel_pub, tel_type, display_tel AS tel, tel_id AS telid, comment
 +              FROM  profile_phones AS t
 +             WHERE  uid = {?} AND link_type = 'address'
 +          ORDER BY  link_id, tel_type DESC, tel_id";
      $restel = XDB::iterator($sql, $uid);
      while ($nexttel = $restel->next()) {
          if (has_user_right($nexttel['tel_pub'], $view)) {
  
  function &get_user_details($login, $from_uid = '', $view = 'private')
  {
 -    $reqsql = "SELECT  u.user_id, u.promo, u.promo_sortie, u.prenom, u.nom, u.nom_usage, u.date, u.cv,
 +    $reqsql = "SELECT  u.user_id, d.promo, u.prenom, u.nom, u.nom_usage, u.date, u.cv,
                         u.perms IN ('admin','user','disabled') AS inscrit,  FIND_IN_SET('femme', u.flags) AS sexe, u.deces != 0 AS dcd, u.deces,
 -                       q.profile_nick AS nickname, q.profile_from_ax, q.profile_mobile AS mobile, q.profile_web AS web, q.profile_freetext AS freetext,
 -                       q.profile_mobile_pub AS mobile_pub, q.profile_web_pub AS web_pub, q.profile_freetext_pub AS freetext_pub,
 -                       q.profile_medals_pub AS medals_pub,
 -                       IF(gp.nat='',gp.pays,gp.nat) AS nationalite, gp.a2 AS iso3166,
 +                       q.profile_nick AS nickname, q.profile_from_ax, q.profile_freetext AS freetext,
 +                       q.profile_freetext_pub AS freetext_pub,
 +                       q.profile_medals_pub AS medals_pub, co.corps_pub AS corps_pub,
 +                       IF(gp1.nat='',gp1.pays,gp1.nat) AS nationalite, gp1.a2 AS iso3166_1,
 +                       IF(gp2.nat='',gp2.pays,gp2.nat) AS nationalite2, gp2.a2 AS iso3166_2,
 +                       IF(gp3.nat='',gp3.pays,gp3.nat) AS nationalite3, gp3.a2 AS iso3166_3,
                         a.alias AS forlife, a2.alias AS bestalias,
                         c.uid IS NOT NULL AS is_contact,
                         s.text AS section, p.x, p.y, p.pub AS photo_pub,
                         u.matricule_ax,
                         m.expertise != '' AS is_referent,
 -                       (COUNT(e.email) > 0 OR FIND_IN_SET('googleapps', u.mail_storage) > 0) AS actif
 -                 FROM  auth_user_md5   AS u
 -           INNER JOIN  auth_user_quick AS q  USING(user_id)
 -           INNER JOIN  aliases         AS a  ON (u.user_id=a.id AND a.type='a_vie')
 -           INNER JOIN  aliases         AS a2 ON (u.user_id=a2.id AND FIND_IN_SET('bestalias',a2.flags))
 -            LEFT JOIN  contacts        AS c  ON (c.uid = {?} and c.contact = u.user_id)
 -            LEFT JOIN  geoloc_pays     AS gp ON (gp.a2 = u.nationalite)
 -           INNER JOIN  sections        AS s  ON (s.id  = u.section)
 -            LEFT JOIN  photo           AS p  ON (p.uid = u.user_id)
 -            LEFT JOIN  mentor          AS m  ON (m.uid = u.user_id)
 -            LEFT JOIN  emails          AS e  ON (e.uid = u.user_id AND e.flags='active')
 +                       (COUNT(e.email) > 0 OR FIND_IN_SET('googleapps', u.mail_storage) > 0) AS actif,
 +                       d.public_name, d.private_name
 +                 FROM  auth_user_md5         AS u
 +           INNER JOIN  auth_user_quick       AS q   USING(user_id)
 +           INNER JOIN  aliases               AS a   ON (u.user_id = a.id AND a.type = 'a_vie')
 +           INNER JOIN  aliases               AS a2  ON (u.user_id = a2.id AND FIND_IN_SET('bestalias', a2.flags))
 +            LEFT JOIN  contacts              AS c   ON (c.uid = {?} and c.contact = u.user_id)
 +            LEFT JOIN  profile_corps         AS co  ON (co.uid = u.user_id)
 +            LEFT JOIN  geoloc_pays           AS gp1 ON (gp1.a2 = u.nationalite)
 +            LEFT JOIN  geoloc_pays           AS gp2 ON (gp2.a2 = u.nationalite2)
 +            LEFT JOIN  geoloc_pays           AS gp3 ON (gp3.a2 = u.nationalite3)
 +           INNER JOIN  sections              AS s   ON (s.id  = u.section)
 +            LEFT JOIN  photo                 AS p   ON (p.uid = u.user_id)
 +            LEFT JOIN  profile_mentor        AS m   ON (m.uid = u.user_id)
 +            LEFT JOIN  emails                AS e   ON (e.uid = u.user_id AND e.flags='active')
 +           INNER JOIN  profile_display       AS d   ON (d.pid = u.user_id)
                  WHERE  a.alias = {?}
               GROUP BY  u.user_id";
      $res  = XDB::query($reqsql, $from_uid, $login);
      $uid  = $user['user_id'];
      // hide orange status, cv, nickname, section
      if (!has_user_right('private', $view)) {
 -        $user['promo_sortie'] = $user['promo'] + 3;
          $user['cv'] = '';
          $user['nickname'] = '';
          $user['section'] = '';
      }
 -    // hide mobile
 -    if (!has_user_right($user['mobile_pub'], $view)) {
 -        if ($user['mobile'] == '')
 -            $user['mobile_pub'] = $view;
 -        else
 -            $user['mobile'] = '';
 -    }
 -    // hide web
 -    if (!has_user_right($user['web_pub'], $view)) {
 -        if ($user['web'] == '')
 -            $user['web_pub'] = $view;
 -        else
 -            $user['web'] = '';
 -    }
 +
      // hide freetext
      if (!has_user_right($user['freetext_pub'], $view)) {
          if ($user['freetext'] == '')
              $user['freetext'] = '';
      }
  
 +    $sql = "SELECT  pub AS tel_pub, tel_type, display_tel AS tel, comment
 +              FROM  profile_phones AS t
 +             WHERE  uid = {?} AND link_type = 'user'
 +          ORDER BY  tel_type DESC, tel_id";
 +    $restel = XDB::iterator($sql, $uid);
 +    while ($nexttel = $restel->next()) {
 +        if (has_user_right($nexttel['tel_pub'], $view)) {
 +            if (!isset($user['tels'])) {
 +                $user['tels'] = array($nexttel);
 +            } else {
 +                $user['tels'][] = $nexttel;
 +            }
 +        }
 +    }
 +
      $user['adr_pro'] = get_user_details_pro($uid, $view);
      $user['adr']     = get_user_details_adr($uid, $view);
  
          $user['binets_join'] = join(', ', $user['binets']);
  
          $res  = XDB::iterRow("SELECT  a.diminutif, a.nom, a.site
-                                 FROM  groupex.asso    AS a
-                            LEFT JOIN  groupex.membres AS m ON (m.asso_id = a.id)
+                                 FROM  #groupex#.asso    AS a
+                            LEFT JOIN  #groupex#.membres AS m ON (m.asso_id = a.id)
                                 WHERE  m.uid = {?} AND (a.cat = 'GroupesX' OR a.cat = 'Institutions')
                                        AND pub = 'public'", $uid);
          $user['gpxs'] = Array();
          $user['gpxs_join'] = join(', ', $user['gpxs']);
      }
  
 -    $res = XDB::iterRow("SELECT  applis_def.text, applis_def.url, applis_ins.type
 -                           FROM  applis_ins
 -                     INNER JOIN  applis_def ON applis_def.id = applis_ins.aid
 -                          WHERE  uid={?}
 -                       ORDER BY  ordre", $uid);
 -
 -    $user['applis_fmt'] = Array();
 -    $user['formation'] = Array();
 -    while (list($txt, $url, $type) = $res->next()) {
 -        $user['formation'][] = $txt." ".$type;
 -        require_once('applis.func.inc.php');
 -        $user['applis_fmt'][] = applis_fmt($type, $txt, $url);
 +    $res = XDB::iterRow("SELECT  en.name AS name, en.url AS url, d.degree AS degree,
 +                                 ed.grad_year AS grad_year, f.field AS field, ed.program AS program
 +                           FROM  profile_education AS ed
 +                      LEFT JOIN  profile_education_enum        AS en ON (en.id = ed.eduid)
 +                      LEFT JOIN  profile_education_degree_enum AS d  ON (d.id  = ed.degreeid)
 +                      LEFT JOIN  profile_education_field_enum  AS f  ON (f.id  = ed.fieldid)
 +                          WHERE  uid = {?} AND NOT FIND_IN_SET('primary', flags)
 +                       ORDER BY  ed.grad_year", $uid);
 +
 +    if (list($name, $url, $degree, $grad_year, $field, $program) = $res->next()) {
 +        require_once('education.func.inc.php');
 +        $user['education'][] = education_fmt($name, $url, $degree, $grad_year, $field, $program, $user['sexe'], true);
 +    }
 +    while (list($name, $url, $degree, $grad_year, $field, $program) = $res->next()) {
 +        $user['education'][] = education_fmt($name, $url, $degree, $grad_year, $field, $program, $user['sexe'], true);
 +    }
 +
 +    if (has_user_right($user['corps_pub'], $view)) {
 +        $res = XDB::query("SELECT  e1.name AS original, e2.name AS current, r.name AS rank
 +                             FROM  profile_corps           AS c
 +                        LEFT JOIN  profile_corps_enum      AS e1 ON (c.original_corpsid = e1.id)
 +                        LEFT JOIN  profile_corps_enum      AS e2 ON (c.current_corpsid = e2.id)
 +                        LEFT JOIN  profile_corps_rank_enum AS r  ON (c.rankid = r.id)
 +                            WHERE  c.uid = {?} AND c.original_corpsid != 1", $uid);
 +        if ($res = $res->fetchOneRow()) {
 +            list($original, $current, $rank) = $res;
 +            $user['corps'] = "Corps d'origine : " . $original . ", corps actuel : " . $current . ", grade : " . $rank;
 +        }
      }
 -    $user['applis_join'] = join(', ', $user['applis_fmt']);
  
      if (has_user_right($user['medals_pub'], $view)) {
          $res = XDB::iterator("SELECT  m.id, m.text AS medal, m.type, s.gid, g.text AS grade
          }
      }
  
 +    $user['networking'] = Array();
 +    $res = XDB::iterator("SELECT  n.address, n.pub, m.network_type AS type, m.name, m.filter, m.link
 +                            FROM  profile_networking AS n
 +                      INNER JOIN  profile_networking_enum AS m ON (n.network_type = m.network_type)
 +                           WHERE  n.uid = {?}", $uid);
 +    while($network = $res->next())
 +    {
 +        if (has_user_right($network['pub'], $view)) {
 +            $network['link'] = str_replace('%s', $network['address'], $network['link']);
 +            $user['networking'][] = $network;
 +        }
 +    }
 +
      return $user;
  }
  // }}}
@@@ -423,7 -386,7 +423,7 @@@ function add_user_address($uid, $adrid
      if (isset($adr['tels']) && is_array($adr['tels'])) {
          $telid = 0;
          foreach ($adr['tels'] as $tel) if ($tel['tel']) {
 -            add_user_tel($uid, $adrid, $telid, $tel);
 +            add_user_tel($uid, 'address', $adrid, $telid, $tel);
              $telid ++;
          }
      }
@@@ -441,17 -404,17 +441,17 @@@ function update_user_address($uid, $adr
          $adr['adr1'], $adr['adr2'], $adr['adr3'],
          $adr['postcode'], $adr['city'], $adr['pub'], $adrid, $uid);
      if (isset($adr['tels']) && is_array($adr['tels'])) {
 -        $res = XDB::query("SELECT telid FROM tels WHERE uid = {?} AND adrid = {?} ORDER BY telid", $uid, $adrid);
 +        $res = XDB::query("SELECT tel_id FROM profile_phones WHERE uid = {?} AND link_type = 'address' AND link_id = {?} ORDER BY tel_id", $uid, $adrid);
          $telids = $res->fetchColumn();
          foreach ($adr['tels'] as $tel) {
              if (isset($tel['telid']) && isset($tel['remove']) && $tel['remove']) {
 -                remove_user_tel($uid, $adrid, $tel['telid']);
 +                remove_user_tel($uid, 'address', $adrid, $tel['telid']);
                  if (isset($telids[$tel['telid']])) unset($telids[$tel['telid']]);
              } else if (isset($tel['telid'])) {
 -                update_user_tel($uid, $adrid, $tel['telid'], $tel);
 +                update_user_tel($uid, 'address', $adrid, $tel['telid'], $tel);
              } else {
                  for ($telid = 0; isset($telids[$telid]) && ($telids[$telid] == $telid); $telid++);
 -                add_user_tel($uid, $adrid, $telid, $tel);
 +                add_user_tel($uid, 'address', $adrid, $telid, $tel);
              }
          }
      }
  // {{{ function remove_user_address()
  function remove_user_address($uid, $adrid) {
      XDB::execute("DELETE FROM adresses WHERE adrid = {?} AND uid = {?}", $adrid, $uid);
 -    XDB::execute("DELETE FROM tels WHERE adrid = {?} AND uid = {?}", $adrid, $uid);
 +    XDB::execute("DELETE FROM profile_phones WHERE link_id = {?} AND uid = {?} AND link_type = 'address'", $adrid, $uid);
  }
  // }}}
  // {{{ function add_user_tel()
 -function add_user_tel($uid, $adrid, $telid, $tel) {
 -    $tel['tel_type'] = ($tel['tel_type'] ? $tel['tel_type'] : '');
 -    XDB::execute('INSERT INTO  tels
 -                          SET  uid = {?}, adrid = {?}, telid = {?}, tel = {?},
 -                               tel_type = {?}, tel_pub = {?}',
 -                 $uid, $adrid, $telid, $tel['tel'], $tel['tel_type'], $tel['tel_pub']);
 +function add_user_tel($uid, $link_type, $link_id, $telid, $tel) {
 +    require('profil.func.inc.php');
 +    $fmt_phone  = format_phone_number($tel['tel']);
 +    $disp_phone = format_display_number($fmt_phone, $error);
 +    XDB::execute("INSERT INTO profile_phones (uid, link_type, link_id, tel_id, tel_type, search_tel, display_tel, pub)
 +                       VALUES ({?}, {?}, {?}, {?}, {?}, {?}, {?}, {?})",
 +                 $uid, $link_type, $link_id, $telid, $tel['tel_type'], $fmt_phone, $disp_phone, $tel['tel_pub']);
  }
  // }}}
  // {{{ function update_user_tel()
 -function update_user_tel($uid, $adrid, $telid, $tel) {
 -    XDB::execute(
 -        "UPDATE tels SET tel = {?}, tel_type = {?}, tel_pub = {?}
 -        WHERE telid = {?} AND adrid = {?} AND uid = {?}",
 -        $tel['tel'], $tel['tel_type'], $tel['tel_pub'],
 -        $telid, $adrid, $uid);
 +function update_user_tel($uid, $link_type, $link_id, $telid, $tel) {
 +    require('profil.func.inc.php');
 +    $fmt_phone  = format_phone_number($tel['tel']);
 +    $disp_phone = format_display_number($fmt_phone, $error);
 +    XDB::execute("UPDATE profile_phones SET search_tel = {?}, display_tel = {?}, tel_type = {?}, pub = {?}
 +                   WHERE link_type = {?} AND tel_id = {?} AND link_id = {?} AND uid = {?}",
 +                 $fmt_phone, $disp_phone, $tel['tel_type'], $tel['tel_pub'],
 +                 $link_type, $telid, $link_id, $uid);
  }
  // }}}
  // {{{ function remove_user_tel()
 -function remove_user_tel($uid, $adrid, $telid) {
 -    XDB::execute("DELETE FROM tels WHERE telid = {?} AND adrid = {?} AND uid = {?}",
 -                 $telid, $adrid, $uid);
 +function remove_user_tel($uid, $link_type, $link_id, $telid) {
 +    XDB::execute("DELETE FROM profile_phones WHERE tel_id = {?} AND link_id = {?} AND uid = {?} AND link_type = {?}",
 +                 $telid, $link_id, $uid, $link_type);
  }
  // }}}
  // {{{ function add_user_pro()
  function add_user_pro($uid, $entrid, $pro) {
      XDB::execute(
          "INSERT INTO entreprises (`uid`, `entrid`, `entreprise`, `poste`, `secteur`, `ss_secteur`, `fonction`,
 -            `adr1`, `adr2`, `adr3`, `postcode`, `city`, `country`, `region`, `tel`, `fax`, `mobile`, `email`, `web`, `pub`, `adr_pub`, `tel_pub`, `email_pub`)
 +            `adr1`, `adr2`, `adr3`, `postcode`, `city`, `country`, `region`, `email`, `web`, `pub`, `adr_pub`, `email_pub`)
          SELECT u.user_id, {?}, {?}, {?}, s.id, ss.id, f.id,
          {?}, {?}, {?}, {?}, {?}, gp.a2, gr.region, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?}
          FROM auth_user_md5 AS u
          WHERE u.user_id = {?}
          LIMIT 1",
          $entrid, $pro['entreprise'], $pro['poste'],
 -        $pro['adr1'], $pro['adr2'], $pro['adr3'], $pro['postcode'], $pro['city'], $pro['tel'], $pro['fax'], $pro['mobile'], $pro['email'], $pro['web'], $pro['pub'], $pro['adr_pub'], $pro['tel_pub'], $pro['email_pub'],
 +        $pro['adr1'], $pro['adr2'], $pro['adr3'], $pro['postcode'], $pro['city'], $pro['email'], $pro['web'], $pro['pub'], $pro['adr_pub'], $pro['email_pub'],
          $pro['secteur'], $pro['sous_secteur'], $pro['fonction'], $pro['fonction'],
          $pro['countrytxt'], $pro['countrytxt'], $pro['region'],
          $uid);
 +    if (isset($pro['tels']) && is_array($pro['tels'])) {
 +        $telid = 0;
 +        foreach ($pro['tels'] as $tel) {
 +            if ($pro['tel']) {
 +                add_user_tel($uid, 'pro', $entrid, $telid, $tel);
 +                $telid ++;
 +            }
 +        }
 +    }
  }
  // }}}
  // {{{ function update_user_pro()
@@@ -556,6 -507,13 +556,6 @@@ function update_user_pro($uid, $entrid
          $args_set[] = $pro['adr_pub'];
      }
  
 -    if (isset($pro['tel'])) {
 -        $set .= ", e.`tel` = {?}, e.`fax` = {?}, e.`mobile` = {?}, e.tel_pub = {?}";
 -        $args_set[] = $pro['tel'];
 -        $args_set[] = $pro['fax'];
 -        $args_set[] = $pro['mobile'];
 -        $args_set[] = $pro['tel_pub'];
 -    }
      if (isset($pro['email'])) {
          $set .= ", e.`email` = {?}, e.`email_pub` = {?}";
          $args_set[] = $pro['email'];
      $args_where = array($uid, $entrid);
      $args = array_merge(array($query), $args_join, $args_set, $args_where);
      call_user_func_array(array('XDB', 'execute'), $args);
 +
 +
 +    if (isset($pro['tels']) && is_array($pro['tels'])) {
 +        $res = XDB::query("SELECT tel_id FROM profile_phones WHERE uid = {?} AND link_type = 'pro' AND link_id = {?} ORDER BY tel_id", $uid, $entrid);
 +        $telids = $res->fetchColumn();
 +        foreach ($pro['tels'] as $tel) {
 +            if (isset($tel['telid']) && isset($tel['remove']) && $tel['remove']) {
 +                remove_user_tel($uid, 'pro', $entrid, $tel['telid']);
 +                if (isset($telids[$tel['telid']])) unset($telids[$tel['telid']]);
 +            } else if (isset($tel['telid'])) {
 +                update_user_tel($uid, 'pro', $entrid, $tel['telid'], $tel);
 +            } else {
 +                for ($telid = 0; isset($telids[$telid]) && ($telids[$telid] == $telid); $telid++);
 +                add_user_tel($uid, 'pro', $entrid, $telid, $tel);
 +            }
 +        }
 +    }
  }
  // }}}
  // {{{ function remove_user_pro()
  function remove_user_pro($uid, $entrid) {
      XDB::execute("DELETE FROM entreprises WHERE entrid = {?} AND uid = {?}", $entrid, $uid);
 +    XDB::execute("DELETE FROM profile_phones WHERE link_id = {?} AND uid = {?} AND link_type = 'pro'", $entrid, $uid);
  }
  // }}}
 -// {{{ function set_user_details()
 +// {{{ function set_user_details_addresses()
  function set_user_details_addresses($uid, $adrs) {
      $req = XDB::query('SELECT MAX(adrid) + 1
                           FROM adresses
@@@ -634,6 -574,9 +634,6 @@@ function set_user_details($uid, $detail
      if (isset($details['nom_usage'])) {
          XDB::execute("UPDATE auth_user_md5 SET nom_usage = {?} WHERE user_id = {?}", mb_strtoupper($details['nom_usage']), $uid);
      }
 -    if (isset($details['mobile'])) {
 -        XDB::execute("UPDATE auth_user_quick SET profile_mobile = {?} WHERE user_id = {?}", $details['mobile'], $uid);
 -    }
      if (isset($details['nationalite'])) {
          XDB::execute(
              "UPDATE auth_user_md5 AS u
                  $uid, $groupex);
          }
      }
 -    // applis
 +    if (isset($details['tels']) && is_array($details['tels'])) {
 +        $res = XDB::query("SELECT tel_id FROM profile_phones WHERE uid = {?} AND link_type = 'user' ORDER BY tel_id", $uid);
 +        $telids = $res->fetchColumn();
 +        foreach ($details['tels'] as $tel) {
 +            if (isset($tel['telid']) && isset($tel['remove']) && $tel['remove']) {
 +                remove_user_tel($uid, 'user', 0, $tel['telid']);
 +                if (isset($telids[$tel['telid']])) unset($telids[$tel['telid']]);
 +            } else if (isset($tel['telid'])) {
 +                update_user_tel($uid, 'user', 0, $tel['telid'], $tel);
 +            } else {
 +                for ($telid = 0; isset($telids[$telid]) && ($telids[$telid] == $telid); $telid++);
 +                add_user_tel($uid, 'user', 0, $telid, $tel);
 +            }
 +        }
 +    }
 +
 +    // education
      // medals
  }
  // }}}
  // {{{ function _user_reindex
  
 -function _user_reindex($uid, $keys, $muls, $pubs)
 +function _user_reindex($uid, $keys)
  {
      foreach ($keys as $i => $key) {
 -        if ($key == '') {
 +        if ($key['name'] == '') {
              continue;
          }
 -        $toks  = preg_split('/[ \'\-]+/', $key);
 +        $toks  = preg_split('/[ \'\-]+/', $key['name']);
          $token = "";
          $first = 5;
          while ($toks) {
              $token = strtolower(replace_accent(array_pop($toks) . $token));
 -            $score = ($toks ? 0 : 10 + $first) * $muls[$i];
 +            $score = ($toks ? 0 : 10 + $first) * ($key['score'] / 10);
              XDB::execute("REPLACE INTO  search_name (token, uid, soundex, score, flags)
                                  VALUES  ({?}, {?}, {?}, {?}, {?})",
 -                         $token, $uid, soundex_fr($token), $score, $pubs[$i] ? 'public' : '');
 +                         $token, $uid, soundex_fr($token), $score, $key['public']);
              $first = 0;
          }
      }
 -    $res = XDB::query("SELECT  nom_ini, nom, nom_usage, prenom_ini, prenom, promo, matricule
 -                         FROM  auth_user_md5
 -                        WHERE  user_id = {?}", $uid);
 -    if (!$res->numRows()) {
 -        unset($res);
 -        return;
 -    }
 -    $array = $res->fetchOneRow();
 -    $promo = intval(array_pop($array));
 -    $mat   = array_shift($array);
 -    array_walk($array, 'soundex_fr');
 -    XDB::execute("REPLACE INTO  recherche_soundex
 -                           SET  matricule = {?}, nom1_soundex = {?}, nom2_soundex= {?}, nom3_soundex = {?},
 -                                prenom1_soundex = {?}, prenom2_soundex= {?}, promo = {?}",
 -                 $mat, $array[0], $array[1], $array[2], $array[3], $array[4], $promo);
 -    unset($res);
 -    unset($array);
  }
  
  // }}}
  // {{{ function user_reindex
  
  function user_reindex($uid) {
 -    XDB::execute("DELETE FROM search_name WHERE uid={?}", $uid);
 -    $res = XDB::query("SELECT prenom, nom, nom_usage, profile_nick FROM auth_user_md5 INNER JOIN auth_user_quick USING(user_id) WHERE auth_user_md5.user_id = {?}", $uid);
 -    if ($res->numRows()) {
 -      _user_reindex($uid, $res->fetchOneRow(), array(1,1,1,0.2), array(true, true, true, false));
 -    } else { // not in auth_user_quick => still "pending"
 -      $res = XDB::query("SELECT prenom, nom, nom_usage FROM auth_user_md5 WHERE auth_user_md5.user_id = {?}", $uid);
 -      if ($res->numRows()) {
 -          _user_reindex($uid, $res->fetchOneRow(), array(1,1,1), array(true, true, true));
 -      }
 -    }
 +    XDB::execute("DELETE FROM  search_name
 +                        WHERE  uid = {?}",
 +                 $uid);
 +    $res = XDB::iterator("SELECT  CONCAT(n.particle, n.name) AS name, e.score,
 +                                  FIND_IN_SET('public', e.flags) AS public
 +                            FROM  profile_name      AS n
 +                      INNER JOIN  profile_name_enum AS e ON (n.typeid = e.id)
 +                           WHERE  n.pid = {?}",
 +                         $uid);
 +    _user_reindex($uid, $res);
  }
  
  // }}}
diff --combined include/userset.inc.php
@@@ -23,22 -23,19 +23,22 @@@ require_once('user.func.inc.php')
  
  global $globals;
  
 -@$globals->search->result_where_statement = '
 -    LEFT JOIN  applis_ins     AS ai0 ON (u.user_id = ai0.uid AND ai0.ordre = 0)
 -    LEFT JOIN  applis_def     AS ad0 ON (ad0.id = ai0.aid)
 -    LEFT JOIN  applis_ins     AS ai1 ON (u.user_id = ai1.uid AND ai1.ordre = 1)
 -    LEFT JOIN  applis_def     AS ad1 ON (ad1.id = ai1.aid)
 -    LEFT JOIN  entreprises    AS e   ON (e.entrid = 0 AND e.uid = u.user_id)
 -    LEFT JOIN  emploi_secteur AS es  ON (e.secteur = es.id)
 -    LEFT JOIN  fonctions_def  AS ef  ON (e.fonction = ef.id)
 -    LEFT JOIN  geoloc_pays    AS n   ON (u.nationalite = n.a2)
 -    LEFT JOIN  adresses       AS adr ON (u.user_id = adr.uid AND FIND_IN_SET(\'active\',adr.statut))
 -    LEFT JOIN  geoloc_pays    AS gp  ON (adr.country = gp.a2)
 -    LEFT JOIN  geoloc_region  AS gr  ON (adr.country = gr.a2 AND adr.region = gr.region)
 -    LEFT JOIN  emails         AS em  ON (em.uid = u.user_id AND em.flags = \'active\')';
 +@$globals->search->result_where_statement = "
 +    LEFT JOIN  profile_education          AS edu ON (u.user_id = edu.uid)
 +    LEFT JOIN  profile_education_enum     AS ede ON (ede.id = edu.eduid)
 +    LEFT JOIN  profile_job                AS j   ON (j.id = 0 AND j.uid = u.user_id)
 +    LEFT JOIN  profile_job_enum           AS je  ON (je.id = j.jobid)
 +    LEFT JOIN  profile_job_sector_enum    AS es  ON (j.sectorid = es.id)
 +    LEFT JOIN  fonctions_def              AS ef  ON (j.functionid = ef.id)
 +    LEFT JOIN  geoloc_countries           AS n1  ON (u.nationalite = n1.iso_3166_1_a2)
 +    LEFT JOIN  geoloc_countries           AS n2  ON (u.nationalite2 = n2.iso_3166_1_a2)
 +    LEFT JOIN  geoloc_countries           AS n3  ON (u.nationalite2 = n3.iso_3166_1_a2)
 +    LEFT JOIN  profile_addresses          AS adr ON (u.user_id = adr.pid
 +                                                     AND FIND_IN_SET('current', adr.flags))
 +    LEFT JOIN  geoloc_countries           AS gc  ON (adr.countryId = gc.iso_3166_1_a2)
 +    LEFT JOIN  geoloc_administrativeareas AS gr  ON (adr.countryId = gr.country
 +                                                     AND adr.administrativeAreaId = gr.id)
 +    LEFT JOIN  emails                     AS em  ON (em.uid = u.user_id AND em.flags = 'active')";
  
  class UserSet extends PlSet
  {
@@@ -47,7 -44,7 +47,7 @@@
          global $globals;
          parent::__construct('auth_user_md5 AS u',
                              (!empty($GLOBALS['IS_XNET_SITE']) ?
-                                 'INNER JOIN groupex.membres AS gxm ON (u.user_id = gxm.uid
+                                 'INNER JOIN #groupex#.membres AS gxm ON (u.user_id = gxm.uid
                                                                         AND gxm.asso_id = ' . $globals->asso('id') . ') ' : '')
                             . 'LEFT JOIN auth_user_quick AS q USING (user_id)' . $joins,
                              $where,
@@@ -159,87 -156,55 +159,87 @@@ class MinificheView extends MultipageVi
  {
      public function __construct(PlSet &$set, $data, array $params)
      {
 -        require_once 'applis.func.inc.php';
 +        require_once 'education.func.inc.php';
          global $globals;
          $this->entriesPerPage = $globals->search->per_page;
          if (@$params['with_score']) {
 -            $this->addSortKey('score', array('-score', '-date', '-promo', 'nom', 'prenom'), 'pertinence');
 +            $this->addSortKey('score', array('-score', '-date', '-d.promo', 'sort_name'), 'pertinence');
          }
 -        $this->addSortKey('name', array('nom', 'prenom'), 'nom');
 -        $this->addSortKey('promo', array('-promo', 'nom', 'prenom'), 'promotion');
 -        $this->addSortKey('date_mod', array('-date', '-promo', 'nom', 'prenom'), 'dernière modification');
 +        $this->addSortKey('name', array('sort_name'), 'nom');
 +        $this->addSortKey('promo', array('-d.promo', 'sort_name'), 'promotion');
 +        $this->addSortKey('date_mod', array('-date', '-d.promo', 'sort_name'), 'dernière modification');
          parent::__construct($set, $data, $params);
      }
  
      public function fields()
      {
          global $globals;
 -        return "u.user_id AS id, u.*,
 +        return "u.user_id AS id, u.*, d.promo,
                  CONCAT(a.alias, '@{$globals->mail->domain}') AS bestemail,
                  u.perms != 'pending' AS inscrit,
                  u.perms != 'pending' AS wasinscrit,
                  u.deces != 0 AS dcd, u.deces, u.matricule_ax,
                  FIND_IN_SET('femme', u.flags) AS sexe,
 -                e.entreprise, e.web AS job_web, es.label AS secteur, ef.fonction_fr AS fonction,
 -                IF(n.nat='',n.pays,n.nat) AS nat, n.a2 AS iso3166,
 -                ad0.text AS app0text, ad0.url AS app0url, ai0.type AS app0type,
 -                ad1.text AS app1text, ad1.url AS app1url, ai1.type AS app1type,
 -                adr.city, gp.a2, gp.pays AS countrytxt, gr.name AS region,
 -                IF(u.nom_usage<>'',u.nom_usage,u.nom) AS sortkey,
 -                (COUNT(em.email) > 0 OR FIND_IN_SET('googleapps', u.mail_storage) > 0) AS actif" .
 +                je.name AS entreprise, je.url AS job_web, es.name AS sector, ef.fonction_fr AS fonction,
 +                IF(n1.nat = '', n1.countryFR, n1.nat) AS nat1, n1.iso_3166_1_a2 AS iso3166_1,
 +                IF(n2.nat = '', n2.countryFR, n2.nat) AS nat2, n2.iso_3166_1_a2 AS iso3166_2,
 +                IF(n3.nat = '', n3.countryFR, n3.nat) AS nat3, n3.iso_3166_1_a2 AS iso3166_3,
 +                IF(ede0.abbreviation = '', ede0.name, ede0.abbreviation) AS eduname0, ede0.url AS eduurl0,
 +                IF(edd0.abbreviation = '', edd0.degree, edd0.abbreviation) AS edudegree0,
 +                edu0.grad_year AS edugrad_year0, f0.field AS edufield0, edu0.program AS eduprogram0,
 +                IF(ede1.abbreviation = '', ede1.name, ede1.abbreviation) AS eduname1, ede1.url AS eduurl1,
 +                IF(edd1.abbreviation = '', edd1.degree, edd1.abbreviation) AS edudegree1,
 +                edu1.grad_year AS edugrad_year1, f1.field AS edufield1, edu1.program AS eduprogram1,
 +                IF(ede2.abbreviation = '', ede2.name, ede2.abbreviation) AS eduname2, ede2.url AS eduurl2,
 +                IF(edd2.abbreviation = '', edd2.degree, edd2.abbreviation) AS edudegree2,
 +                edu2.grad_year AS edugrad_year2, f2.field AS edufield2, edu2.program AS eduprogram2,
 +                IF(ede3.abbreviation = '', ede3.name, ede3.abbreviation) AS eduname3, ede3.url AS eduurl3,
 +                IF(edd3.abbreviation = '', edd3.degree, edd3.abbreviation) AS edudegree3,
 +                edu3.grad_year AS edugrad_year3, f3.field AS edufield3, edu3.program AS eduprogram3,
 +                "// adr.localityId, gr.name AS region
 +              . "gc.iso_3166_1_a2, gc.countryFR AS countrytxt
 +                (COUNT(em.email) > 0 OR FIND_IN_SET('googleapps', u.mail_storage) > 0) AS actif,
 +                d.directory_name, d.sort_name" .
                  (S::logged() ? ", c.contact AS contact" : '');
      }
  
      public function joins()
      {
 -        return  "LEFT JOIN  entreprises    AS e   ON (e.entrid = 0 AND e.uid = u.user_id".(S::logged() ? "" : " AND e.pub = 'public'").")
 -                 LEFT JOIN  emploi_secteur AS es  ON (e.secteur = es.id)
 -                 LEFT JOIN  fonctions_def  AS ef  ON (e.fonction = ef.id)
 -                 LEFT JOIN  geoloc_pays    AS n   ON (u.nationalite = n.a2)
 -                 LEFT JOIN  applis_ins     AS ai0 ON (u.user_id = ai0.uid AND ai0.ordre = 0)
 -                 LEFT JOIN  applis_def     AS ad0 ON (ad0.id = ai0.aid)
 -                 LEFT JOIN  applis_ins     AS ai1 ON (u.user_id = ai1.uid AND ai1.ordre = 1)
 -                 LEFT JOIN  applis_def     AS ad1 ON (ad1.id = ai1.aid)
 -                 LEFT JOIN  adresses       AS adr ON (u.user_id = adr.uid
 -                                                      AND FIND_IN_SET('active', adr.statut)".(S::logged() ? "" : " AND adr.pub = 'public'").")
 -                 LEFT JOIN  geoloc_pays    AS gp  ON (adr.country = gp.a2)
 -                 LEFT JOIN  geoloc_region  AS gr  ON (adr.country = gr.a2 AND adr.region = gr.region)
 -                 LEFT JOIN  aliases        AS a   ON (a.id = u.user_id AND FIND_IN_SET('bestalias', a.flags))
 -                 LEFT JOIN  emails         AS em  ON (em.uid = u.user_id AND em.flags = 'active')" .
 -                (S::logged() ?
 -                 "LEFT JOIN  contacts       AS c   On (c.contact = u.user_id AND c.uid = " . S::v('uid') . ")"
 +        return  "LEFT JOIN  aliases                       AS a    ON (u.user_id = a.id AND FIND_IN_SET('bestalias', a.flags))
 +                 LEFT JOIN  search_name                   AS n    ON (u.user_id = n.uid)
 +                 LEFT JOIN  profile_job                   AS j    ON (j.uid = u.user_id".(S::logged() ? "" : " AND j.pub = 'public'").")
 +                 LEFT JOIN  profile_job_enum              AS je   ON (je.id = j.jobid)
 +                 LEFT JOIN  profile_job_sector_enum       AS es   ON (j.sectorid = es.id)
 +                 LEFT JOIN  fonctions_def                 AS ef   ON (j.functionid = ef.id)
 +                 LEFT JOIN  geoloc_countries              AS n1   ON (u.nationalite = n1.iso_3166_1_a2)
 +                 LEFT JOIN  geoloc_countries              AS n2   ON (u.nationalite2 = n2.iso_3166_1_a2)
 +                 LEFT JOIN  geoloc_countries              AS n3   ON (u.nationalite3 = n3.iso_3166_1_a2)
 +                 LEFT JOIN  profile_education             AS edu0 ON (u.user_id = edu0.uid AND edu0.id = 0)
 +                 LEFT JOIN  profile_education_enum        AS ede0 ON (ede0.id = edu0.eduid)
 +                 LEFT JOIN  profile_education_degree_enum AS edd0 ON (edd0.id = edu0.degreeid)
 +                 LEFT JOIN  profile_education_field_enum  AS f0   ON (f0.id = edu0.fieldid)
 +                 LEFT JOIN  profile_education             AS edu1 ON (u.user_id = edu1.uid AND edu1.id = 1)
 +                 LEFT JOIN  profile_education_enum        AS ede1 ON (ede1.id = edu1.eduid)
 +                 LEFT JOIN  profile_education_degree_enum AS edd1 ON (edd1.id = edu1.degreeid)
 +                 LEFT JOIN  profile_education_field_enum  AS f1   ON (f1.id = edu1.fieldid)
 +                 LEFT JOIN  profile_education             AS edu2 ON (u.user_id = edu2.uid AND edu2.id = 2)
 +                 LEFT JOIN  profile_education_enum        AS ede2 ON (ede2.id = edu2.eduid)
 +                 LEFT JOIN  profile_education_degree_enum AS edd2 ON (edd2.id = edu2.degreeid)
 +                 LEFT JOIN  profile_education_field_enum  AS f2   ON (f2.id = edu2.fieldid)
 +                 LEFT JOIN  profile_education             AS edu3 ON (u.user_id = edu3.uid AND edu3.id = 3)
 +                 LEFT JOIN  profile_education_enum        AS ede3 ON (ede3.id = edu3.eduid)
 +                 LEFT JOIN  profile_education_degree_enum AS edd3 ON (edd3.id = edu3.degreeid)
 +                 LEFT JOIN  profile_education_field_enum  AS f3   ON (f3.id = edu3.fieldid)
 +                 LEFT JOIN  profile_addresses             AS adr  ON (u.user_id = adr.pid
 +                                                                      AND FIND_IN_SET('current', adr.flags)"
 +                                                                      . (S::logged() ? "" :
 +                                                                         "AND adr.pub = 'public'") . ")
 +                 LEFT JOIN  geoloc_countries              AS gc   ON (adr.countryId = gc.iso_3166_a2)
 +                 LEFT JOIN  geoloc_administrativeareas    AS gr   ON (adr.countryId = gr.country
 +                                                                      AND adr.administrativeAreaId = gr.id)
 +                 LEFT JOIN  emails                        AS em   ON (em.uid = u.user_id AND em.flags = 'active')
 +                INNER JOIN  profile_display               AS d    ON (d.pid = u.user_id)" . (S::logged() ?
 +                "LEFT JOIN  contacts                      AS c    ON (c.contact = u.user_id AND c.uid = " . S::v('uid') . ")"
                   : "");
      }
  
@@@ -272,22 -237,16 +272,22 @@@ class MentorView extends MultipageVie
      {
          $this->entriesPerPage = 10;
          $this->addSortKey('rand', array('RAND(' . S::i('uid') . ')'), 'aléatoirement');
 -        $this->addSortKey('name', array('nom', 'prenom'), 'nom');
 -        $this->addSortKey('promo', array('-promo', 'nom', 'prenom'), 'promotion');
 -        $this->addSortKey('date_mod', array('-date', '-promo', 'nom', 'prenom'), 'dernière modification');
 +        $this->addSortKey('name', array('sort_name'), 'nom');
 +        $this->addSortKey('promo', array('-d.promo', 'sort_name'), 'promotion');
 +        $this->addSortKey('date_mod', array('-date', '-d.promo', 'sort_name'), 'dernière modification');
          parent::__construct($set, $data, $params);
      }
  
      public function fields()
      {
 -        return "m.uid, u.prenom, u.nom, u.promo, u.hruid,
 -                m.expertise, mp.pid, ms.secteur, ms.ss_secteur";
 +        return "m.uid, d.promo, u.hruid,
 +                m.expertise, mp.country, ms.sectorid, ms.subsectorid,
 +                d.directory_name, d.sort_name";
 +    }
 +
 +    public function joins()
 +    {
 +        return "INNER JOIN  profile_display AS d ON (d.pid = u.user_id)";
      }
  
      public function bounds()
@@@ -318,24 -277,23 +318,24 @@@ class TrombiView extends MultipageVie
      public function __construct(PlSet &$set, $data, array $params)
      {
          $this->entriesPerPage = 24;
 -        $this->order = explode(',', Env::v('order', 'nom,prenom,promo'));
 +        $this->order = explode(',', Env::v('order', 'sort_name'));
          if (@$params['with_score']) {
 -            $this->addSortKey('score', array('-score', '-watch_last', '-promo', 'nom', 'prenom'), 'pertinence');
 +            $this->addSortKey('score', array('-score', '-watch_last', '-d.promo', 'sort_name'), 'pertinence');
          }
 -        $this->addSortKey('name', array('nom', 'prenom'), 'nom');
 -        $this->addSortKey('promo', array('-promo', 'nom', 'prenom'), 'promotion');
 +        $this->addSortKey('name', array('sort_name'), 'nom');
 +        $this->addSortKey('promo', array('-d.promo', 'sort_name'), 'promotion');
          parent::__construct($set, $data, $params);
      }
  
      public function fields()
      {
 -        return "u.user_id, IF(u.nom_usage != '', u.nom_usage, u.nom) AS nom, u.prenom, u.promo, u.hruid ";
 +        return "u.user_id, d.directory_name, d.sort_name, u.promo, d.promo, u.hruid ";
      }
  
      public function joins()
      {
 -        return "INNER JOIN  photo AS p ON (p.uid = u.user_id) ";
 +        return "INNER JOIN  photo           AS p  ON (p.uid = u.user_id)
 +                INNER JOIN  profile_display AS d  ON (d.pid = u.user_id)";
      }
  
      public function bounds()
      }
  }
  
 -class GeolocView implements PlView
 -{
 -    private $set;
 -    private $type;
 -    private $params;
 -
 -    public function __construct(PlSet &$set, $data, array $params)
 -    {
 -        $this->params = $params;
 -        $this->set   =& $set;
 -        $this->type   = $data;
 -    }
 -
 -    private function use_map()
 -    {
 -        return is_file(dirname(__FILE__) . '/../modules/geoloc/dynamap.swf') &&
 -               is_file(dirname(__FILE__) . '/../modules/geoloc/icon.swf');
 -    }
 -
 -    public function args()
 -    {
 -        $args = $this->set->args();
 -        unset($args['initfile']);
 -        unset($args['mapid']);
 -        return $args;
 -    }
 -
 -    public function apply(PlPage &$page)
 -    {
 -        require_once 'geoloc.inc.php';
 -        require_once '../modules/search/search.inc.php';
 -
 -        switch ($this->type) {
 -          case 'icon.swf':
 -            pl_cached_content_headers("application/x-shockwave-flash");
 -            readfile(dirname(__FILE__).'/../modules/geoloc/icon.swf');
 -            exit;
 -
 -          case 'dynamap.swf':
 -            pl_cached_content_headers("application/x-shockwave-flash");
 -            readfile(dirname(__FILE__).'/../modules/geoloc/dynamap.swf');
 -            exit;
 -
 -          case 'init':
 -            $page->changeTpl('geoloc/init.tpl', NO_SKIN);
 -            pl_cached_content_headers("text/xml", "utf-8");
 -            if (!empty($GLOBALS['IS_XNET_SITE'])) {
 -                $page->assign('background', 0xF2E9D0);
 -            }
 -            break;
 -
 -          case 'city':
 -            $page->changeTpl('geoloc/city.tpl', NO_SKIN);
 -            pl_cached_content_headers("text/xml", "utf-8");
 -            $only_current = Env::v('only_current', false)? ' AND FIND_IN_SET(\'active\', adrf.statut)' : '';
 -            $it =& $this->set->get('u.user_id AS id, u.prenom, u.nom, u.promo, al.alias',
 -                                   "INNER JOIN  adresses AS adrf  ON (adrf.uid = u.user_id $only_current)
 -                                     LEFT JOIN  aliases  AS al   ON (u.user_id = al.id
 -                                                                   AND FIND_IN_SET('bestalias', al.flags))
 -                                    INNER JOIN  adresses AS avg ON (" . getadr_join('avg') . ")",
 -                                   'adrf.cityid = ' . Env::i('cityid'), null, null, 11);
 -            $page->assign('users', $it);
 -            break;
 -
 -          case 'country':
 -            if (Env::has('debug')) {
 -                $page->changeTpl('geoloc/country.tpl', SIMPLE);
 -            } else {
 -                $page->changeTpl('geoloc/country.tpl', NO_SKIN);
 -                pl_cached_content_headers("text/xml", "utf-8");
 -            }
 -            $mapid = Env::has('mapid') ? Env::i('mapid', -2) : false;
 -            list($countries, $cities) = geoloc_getData_subcountries($mapid, $this->set, 10);
 -            $page->assign('countries', $countries);
 -            $page->assign('cities', $cities);
 -            break;
 -
 -          default:
 -            global $globals;
 -            if (!$this->use_map()) {
 -                $page->assign('request_geodesix', true);
 -            }
 -            $page->assign('annu', @$this->params['with_annu']);
 -            $page->assign('protocole', @$_SERVER['HTTPS'] ? 'https' : 'http');
 -            $this->set->get('u.user_id', null, "u.perms != 'pending' AND u.deces = 0", "u.user_id", null);
 -            return 'include/plview.geoloc.tpl';
 -        }
 -    }
 -}
 -
  class GadgetView implements PlView
  {
      public function __construct(PlSet &$set, $data, array $params)
      public function fields()
      {
          return "u.user_id AS id, u.*," .
 -                (S::logged() ? "q.profile_mobile AS mobile, " : "IF(q.profile_mobile_pub = 'public', q.profile_mobile, NULL) as mobile, ") .
                 "u.perms != 'pending' AS inscrit,
                  u.perms != 'pending' AS wasinscrit,
                  u.deces != 0 AS dcd, u.deces,
                  FIND_IN_SET('femme', u.flags) AS sexe,
 -                adr.city, gp.a2, gp.pays AS countrytxt, gr.name AS region" .
 +                " // adr.city, gr.name AS region
 +              . "gc.iso_3166_1_a2, gc.countryFR AS countrytxt" .
                  (S::logged() ? ", c.contact AS contact" : '');
      }
  
      public function joins()
      {
 -        return  "LEFT JOIN  adresses       AS adr ON (u.user_id = adr.uid AND FIND_IN_SET('active', adr.statut)".(S::logged() ? "" : " AND adr.pub = 'public'").")
 -                 LEFT JOIN  geoloc_pays    AS gp  ON (adr.country = gp.a2)
 -                 LEFT JOIN  geoloc_region  AS gr  ON (adr.country = gr.a2 AND adr.region = gr.region)" .
 -                (S::logged() ?
 -                 "LEFT JOIN  contacts       AS c   On (c.contact = u.user_id AND c.uid = " . S::v('uid') . ")"
 -                 : "");
 +        return "LEFT JOIN  profile_addresses          AS adr ON (u.user_id = adr.pid AND
 +                                                                 FIND_IN_SET('current', adr.flags)"
 +                                                                . (S::logged() ? "" : "AND adr.pub = 'public'") . ")
 +                LEFT JOIN  geoloc_countries           AS gc  ON (adr.countryId = gc.iso_3166_1_a2)
 +                LEFT JOIN  geoloc_administrativeareas AS gr  ON (adr.countryId = gr.country
 +                                                                 AND adr.administrativeAreaId = gr.id)
 +               " . (S::logged() ?
 +               "LEFT JOIN  contacts                   AS c   ON (c.contact = u.user_id
 +                                                                 AND c.uid = " . S::v('uid') . ")" : "");
      }
  
      public function apply(PlPage &$page)
diff --combined modules/admin.php
@@@ -48,7 -48,6 +48,7 @@@ class AdminModule extends PLModul
              'admin/ipwatch'                => $this->make_hook('ipwatch',                AUTH_MDP, 'admin'),
              'admin/icons'                  => $this->make_hook('icons',                  AUTH_MDP, 'admin'),
              'admin/accounts'               => $this->make_hook('accounts',               AUTH_MDP, 'admin'),
 +            'admin/jobs'                   => $this->make_hook('jobs',                   AUTH_MDP, 'admin'),
          );
      }
  
                                        MONTH(MAX(start)), MONTH(MIN(start)),
                                        DAYOFMONTH(MAX(start)),
                                        DAYOFMONTH(MIN(start))
-                                  FROM logger.sessions");
+                                  FROM #logger#.sessions");
              list($ymax, $ymin, $mmax, $mmin, $dmax, $dmin) = $res->fetchOneRow();
  
              if (($year < $ymin) || ($year == $ymin && $month < $mmin)) {
          if ($year) {
              $res = XDB::query("SELECT YEAR (MAX(start)), YEAR (MIN(start)),
                                        MONTH(MAX(start)), MONTH(MIN(start))
-                                  FROM logger.sessions");
+                                  FROM #logger#.sessions");
              list($ymax, $ymin, $mmax, $mmin) = $res->fetchOneRow();
  
              if (($year < $ymin) || ($year > $ymax)) {
          $years[0] = "----";
  
          // retrieve available years
-         $res = XDB::query("select YEAR(MAX(start)), YEAR(MIN(start)) FROM logger.sessions");
+         $res = XDB::query("select YEAR(MAX(start)), YEAR(MIN(start)) FROM #logger#.sessions");
          list($max, $min) = $res->fetchOneRow();
  
          for($i = intval($min); $i<=$max; $i++) {
  
              // we are viewing a session
              $res = XDB::query("SELECT  ls.*, a.alias AS username, sa.alias AS suer
-                                  FROM  logger.sessions AS ls
-                             LEFT JOIN  aliases         AS a  ON (a.id = ls.uid AND a.type='a_vie')
-                             LEFT JOIN  aliases         AS sa ON (sa.id = ls.suid AND sa.type='a_vie')
+                                  FROM  #logger#.sessions AS ls
+                             LEFT JOIN  #x4dat#.aliases   AS a  ON (a.id = ls.uid AND a.type='a_vie')
+                             LEFT JOIN  #x4dat#.aliases   AS sa ON (sa.id = ls.suid AND sa.type='a_vie')
                                  WHERE  ls.id = {?}", $arg);
  
              $page->assign('session', $a = $res->fetchOneAssoc());
  
              $res = XDB::iterator('SELECT  a.text, e.data, e.stamp
-                                     FROM  logger.events  AS e
-                                LEFT JOIN  logger.actions AS a ON e.action=a.id
+                                     FROM  #logger#.events  AS e
+                                LEFT JOIN  #logger#.actions AS a ON e.action=a.id
                                     WHERE  e.session={?}', $arg);
              while ($myarr = $res->next()) {
                 $page->append('events', $myarr);
                  $where  = $this->_makeWhere($year, $month, $day, $loguid);
                  $select = "SELECT  s.id, s.start, s.uid,
                                     a.alias as username
-                              FROM  logger.sessions AS s
-                         LEFT JOIN  aliases         AS a  ON (a.id = s.uid AND a.type='a_vie')
+                              FROM  #logger#.sessions AS s
+                         LEFT JOIN  #x4dat#.aliases   AS a  ON (a.id = s.uid AND a.type='a_vie')
                      $where
                      ORDER BY start DESC";
                  $res = XDB::iterator($select);
  
                  // attach events
                  $sql = "SELECT  s.id, a.text
-                           FROM  logger.sessions AS s
-                     LEFT  JOIN  logger.events   AS e ON(e.session=s.id)
-                     INNER JOIN  logger.actions  AS a ON(a.id=e.action)
+                           FROM  #logger#.sessions AS s
+                     LEFT  JOIN  #logger#.events   AS e ON(e.session=s.id)
+                     INNER JOIN  #logger#.actions  AS a ON(a.id=e.action)
                          $where";
  
                  $res = XDB::iterator($sql);
  
                  // Forum ban update.
                  case "b_edit":
-                     XDB::execute("DELETE FROM forums.innd WHERE uid = {?}", $user->id());
+                     XDB::execute("DELETE FROM #forums#.innd WHERE uid = {?}", $user->id());
                      if (Env::v('write_perm') != "" || Env::v('read_perm') != ""  || Env::v('commentaire') != "" ) {
-                         XDB::execute("INSERT INTO  forums.innd
+                         XDB::execute("INSERT INTO  #forums#.innd
                                                SET  ipmin = '0', ipmax = '4294967295',
                                                     write_perm = {?}, read_perm = {?},
                                                     comment = {?}, priority = '200', uid = {?}",
  
          // Displays last login and last host information.
          $res = XDB::query("SELECT  start, host
-                              FROM  logger.sessions
+                              FROM  #logger#.sessions
                              WHERE  uid = {?} AND suid = 0
                           ORDER BY  start DESC
                              LIMIT  1", $user->id());
  
          // Displays forum bans.
          $res = XDB::query("SELECT  write_perm, read_perm, comment
-                              FROM  forums.innd
+                              FROM  #forums#.innd
                              WHERE  uid = {?}", $user->id());
          $bans = $res->fetchOneAssoc();
          $page->assign('bans', $bans);
                  $action = Env::v('valid_promo') == 'Ajouter des membres' ? 'add' : 'ax';
                  pl_redirect('admin/promo/' . $action . '/' . Env::i('promo'));
              } else {
 -                $page->trigError('Promo non valide');
 +                $page->trigError('Promotion non valide.');
              }
          }
  
  
          $res = XDB::iterator(
                  "SELECT  u.promo, u.nom, u.prenom, u.deces, u.hruid, DATE(MAX(s.start)) AS last
-                    FROM  auth_user_md5 AS u
-               LEFT JOIN  logger.sessions AS s ON (s.uid = u.user_id AND suid = 0)
+                    FROM  #x4dat#.auth_user_md5 AS u
+               LEFT JOIN  #logger#.sessions     AS s ON (s.uid = u.user_id AND suid = 0)
                    WHERE  perms IN ('admin', 'user') AND deces <> 0
                 GROUP BY  u.user_id
                 ORDER BY  u.promo, u.nom");
      function handler_logger_actions(&$page, $action = 'list', $id = null) {
          $page->setTitle('Administration - Actions');
          $page->assign('title', 'Gestion des actions de logger');
-         $table_editor = new PLTableEditor('admin/logger/actions','logger.actions','id');
+         $table_editor = new PLTableEditor('admin/logger/actions','#logger#.actions','id');
          $table_editor->describe('text','intitulé',true);
          $table_editor->describe('description','description',true);
          $table_editor->apply($page, $action, $id);
          }
  
          $page->changeTpl('admin/wiki.tpl');
-         $page->addJsLink('jquery.js');
          $page->assign('wiki_pages', $wiki_tree);
          $page->assign('perms_opts', $perms);
      }
                                       IF(w.ip = s2.ip, s2.host, s2.forward_host),
                                       IF(w.ip = s.ip, s.host, s.forward_host)),
                              w.mask, w.detection, w.state, u.hruid
-                       FROM  ip_watch        AS w
-                  LEFT JOIN  logger.sessions AS s  ON (s.ip = w.ip)
-                  LEFT JOIN  logger.sessions AS s2 ON (s2.forward_ip = w.ip)
-                  LEFT JOIN  auth_user_md5   AS u  ON (u.user_id = s.uid)
+                       FROM  #x4dat#.ip_watch      AS w
+                  LEFT JOIN  #logger#.sessions     AS s  ON (s.ip = w.ip)
+                  LEFT JOIN  #logger#.sessions     AS s2 ON (s2.forward_ip = w.ip)
+                  LEFT JOIN  #x4dat#.auth_user_md5 AS u  ON (u.user_id = s.uid)
                    GROUP BY  w.ip, u.hruid
                    ORDER BY  w.state, w.ip, u.hruid";
              $it = Xdb::iterRow($sql);
          } elseif ($action == 'edit') {
              $sql = "SELECT  w.detection, w.state, w.last, w.description, w.mask,
                              u1.hruid AS edit, u2.hruid AS hruid, s.host
-                       FROM  ip_watch        AS w
-                  LEFT JOIN  auth_user_md5   AS u1 ON (u1.user_id = w.uid)
-                  LEFT JOIN  logger.sessions AS s  ON (w.ip = s.ip)
-                  LEFT JOIN  auth_user_md5   AS u2 ON (u2.user_id = s.uid)
+                       FROM  #x4dat#.ip_watch      AS w
+                  LEFT JOIN  #x4dat#.auth_user_md5 AS u1 ON (u1.user_id = w.uid)
+                  LEFT JOIN  #logger#.sessions     AS s  ON (w.ip = s.ip)
+                  LEFT JOIN  #x4dat#.auth_user_md5 AS u2 ON (u2.user_id = s.uid)
                       WHERE  w.ip = {?}
                    GROUP BY  u2.hruid
                    ORDER BY  u2.hruid";
                                                  WHERE  perms = \'admin\'
                                               ORDER BY  nom, prenom'));
      }
 +
 +    function handler_jobs(&$page, $id = -1)
 +    {
 +        $page->changeTpl('admin/jobs.tpl');
 +
 +        if (Env::has('search')) {
 +            $res = XDB::query("SELECT  e.id, e.name, e.acronym
 +                                 FROM  profile_job_enum AS e
 +                                WHERE  e.name LIKE CONCAT('% ', {?}, '%') OR e.acronym LIKE CONCAT('% ', {?}, '%')",
 +                              Env::t('job'), Env::t('job'));
 +
 +            if ($res->numRows() <= 20) {
 +                $page->assign('jobs', $res->fetchAllAssoc());
 +            } else {
 +                $page->trigError("Il y a trop d'entreprises correspondant à ton choix. Affine-le !");
 +            }
 +
 +            $page->assign('askedJob', Env::v('job'));
 +            return;
 +        }
 +
 +        if (Env::has('edit')) {
 +            // TODO: use address and phone classes to update profile_job_enum and profile_phones once they are done.
 +
 +            S::assert_xsrf_token();
 +            $selectedJob = Env::has('selectedJob');
 +
 +            XDB::execute("DELETE FROM  profile_phones
 +                                WHERE  uid = {?} AND link_type = 'hq'",
 +                         $id);
 +            XDB::execute("DELETE FROM  profile_addresses
 +                                WHERE  jobid = {?} AND type = 'hq'",
 +                         $id);
 +            XDB::execute('DELETE FROM  profile_job_enum
 +                                WHERE  id = {?}',
 +                         $id);
 +
 +            if (Env::has('change')) {
 +                XDB::execute('UPDATE  profile_job
 +                                 SET  jobid = {?}
 +                               WHERE  jobid = {?}',
 +                             Env::i('newJobId'), $id);
 +
 +                $page->trigSuccess("L'entreprise a bien été remplacée.");
 +            } else {
 +                require_once 'profil.func.inc.php';
 +                require_once 'geocoding.inc.php';
 +
 +                $display_tel = format_display_number(Env::v('tel'), $error_tel);
 +                $display_fax = format_display_number(Env::v('fax'), $error_fax);
 +                $gmapsGeocoder = new GMapsGeocoder();
 +                $address = array('text' => Env::t('address'));
 +                $address = $gmapsGeocoder->getGeocodedAddress($address);
 +                Geocoder::getAreaId($address, 'administrativeArea');
 +                Geocoder::getAreaId($address, 'subAdministrativeArea');
 +                Geocoder::getAreaId($address, 'locality');
 +
 +                XDB::execute('UPDATE  profile_job_enum
 +                                 SET  name = {?}, acronym = {?}, url = {?}, email = {?},
 +                                      NAF_code = {?}, AX_code = {?}, holdingid = {?}
 +                               WHERE  id = {?}',
 +                             Env::t('name'), Env::t('acronym'), Env::t('url'), Env::t('email'),
 +                             Env::t('NAF_code'), Env::i('AX_code'), Env::i('holdingId'), $id);
 +
 +                XDB::execute("INSERT INTO  profile_phones (uid, link_type, link_id, tel_id, tel_type,
 +                                           search_tel, display_tel, pub)
 +                                   VALUES  ({?}, 'hq', 0, 0, 'fixed', {?}, {?}, 'public'),
 +                                           ({?}, 'hq', 0, 1, 'fax', {?}, {?}, 'public')",
 +                             $id, format_phone_number(Env::v('tel')), $display_tel,
 +                             $id, format_phone_number(Env::v('fax')), $display_fax);
 +
 +                XDB::execute("INSERT INTO  profile_addresses (jobid, type, id, accuracy,
 +                                                              text, postalText, postalCode, localityId,
 +                                                              subAdministrativeAreaId, administrativeAreaId,
 +                                                              countryId, latitude, longitude, updateTime,
 +                                                              north, south, east, west)
 +                                   VALUES  ({?}, 'hq', 0, {?}, {?}, {?}, {?}, {?}, {?}, {?}, {?},
 +                                            {?}, {?}, FROM_UNIXTIME({?}), {?}, {?}, {?}, {?})",
 +                             $id, $address['accuracy'], $address['text'], $address['postalText'],
 +                             $address['postalCode'], $address['localityId'],
 +                             $address['subAdministrativeAreaId'], $address['administrativeAreaId'],
 +                             $address['countryId'], $address['latitude'], $address['longitude'],
 +                             $address['updateTime'], $address['north'], $address['south'],
 +                             $address['east'], $address['west']);
 +
 +                $page->trigSuccess("L'entreprise a bien été mise à jour.");
 +            }
 +        }
 +
 +        if (!Env::has('change') && $id != -1) {
 +            $res = XDB::query("SELECT  e.id, e.name, e.acronym, e.url, e.email, e.NAF_code, e.AX_code,
 +                                       h.id AS holdingId, h.name AS holdingName, h.acronym AS holdingAcronym,
 +                                       t.display_tel AS tel, f.display_tel AS fax, a.text AS address
 +                                 FROM  profile_job_enum  AS e
 +                            LEFT JOIN  profile_job_enum  AS h ON (e.holdingid = h.id)
 +                            LEFT JOIN  profile_phones    AS t ON (t.uid = e.id AND link_type = 'hq' AND tel_id = 0)
 +                            LEFT JOIN  profile_phones    AS f ON (f.uid = e.id AND link_type = 'hq' AND tel_id = 1)
 +                            LEFT JOIN  profile_addresses AS a ON (a.jobid = e.id AND a.type = 'hq')
 +                                WHERE  e.id = {?}",
 +                              $id);
 +
 +            if ($res->numRows() == 0) {
 +                $page->trigError('Auncune entreprise ne correspond à cet identifiant.');
 +            } else {
 +                $page->assign('selectedJob', $res->fetchOneAssoc());
 +            }
 +        }
 +    }
  }
  
  // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
diff --combined modules/email.php
@@@ -260,15 -260,7 +260,15 @@@ class EmailModule extends PLModul
              $actifs = Env::v('emails_actifs', Array());
              print_r(Env::v('emails_rewrite'));
              if (Env::v('emailop') == "ajouter" && Env::has('email')) {
 -                $result = $redirect->add_email(Env::v('email'));
 +                $new_email = Env::v('email');
 +                if ($new_email == "new@example.org") {
 +                    $new_email = Env::v('email_new');
 +                }
 +                $result = $redirect->add_email($new_email);
 +                if ($result == ERROR_INVALID_EMAIL) {
 +                    $page->assign('email', $new_email);
 +                }
 +                $page->assign('retour', $result);
              } elseif (empty($actifs)) {
                  $result = ERROR_INACTIVE_REDIRECTION;
              } elseif (is_array($actifs)) {
          // Display GoogleApps acount information.
          require_once 'googleapps.inc.php';
          $page->assign('googleapps', GoogleAppsAccount::account_status($user->id()));
 +
 +        require_once 'emails.combobox.inc.php';
 +        fill_email_combobox($page);
      }
  
      function handler_antispam(&$page, $statut_filtre = null)
                  $to2  = getEmails(Env::v('to_contacts'));
                  $cc2  = getEmails(Env::v('cc_contacts'));
                  $txt  = str_replace('^M', '', Env::v('contenu'));
-                 $to   = Env::v('to');
-                 $subj = Env::v('sujet');
-                 $from = Env::v('from');
-                 $cc   = trim(Env::v('cc'));
-                 $bcc  = trim(Env::v('bcc'));
+                 $to   = str_replace(';', ',', Env::t('to'));
+                 $subj = Env::t('sujet');
+                 $from = Env::t('from');
+                 $cc   = str_replace(';', ',', Env::t('cc'));
+                 $bcc  = str_replace(';', ',', Env::t('bcc'));
+                 $email_regex = '/^[a-z0-9.\-+_\$]+@([\-.+_]?[a-z0-9])+$/i';
+                 foreach (explode(',', $to . ',' . $cc . ',' . $bcc) as $email) {
+                     $email = trim($email);
+                     if ($email != '' && !preg_match($email_regex, $email)) {
+                         $page->trigError("L'adresse email " . $email  . ' est erronée.');
+                         $error = true;
+                     }
+                 }
                  if (empty($to) && empty($cc) && empty($to2) && empty($bcc) && empty($cc2)) {
                      $page->trigError("Indique au moins un destinataire.");
+                     $error = true;
+                 }
+                 if ($error) {
                      $page->assign('uploaded_f', PlUpload::listFilenames(S::user()->login(), 'emails.send'));
                  } else {
                      $mymail = new PlMailer();
@@@ -835,8 -836,8 +847,8 @@@ L'équipe d'administration <support@" 
                  foreach ($broken_list as $orig_email) {
                      $email = valide_email(trim($orig_email));
                      if (empty($email) || $email == '@') {
-                         $invalid_emails[] = "$orig_email: invalid email";
-                     } else {
+                         $invalid_emails[] = trim($orig_email) . ': invalid email';
+                     } elseif (!in_array($email, $valid_emails)) {
                          $res = XDB::query('SELECT  COUNT(*)
                                               FROM  emails
                                              WHERE  email = {?}', $email);
  
                  // Output the list of users with recently broken addresses,
                  // along with the count of valid redirections.
-                 header('Content-Type: text/x-csv; charset=utf-8;');
-                 header('Cache-Control: no-cache');
+                 require_once 'include/notifs.inc.php';
+                 pl_content_headers("text/x-csv");
  
                  $csv = fopen('php://output', 'w');
-                 fputcsv($csv, array('nom', 'prenom', 'alias', 'bounce', 'nbmails', 'url'), ';');
+                 fputcsv($csv, array('nom', 'prenom', 'promo', 'alias', 'bounce', 'nbmails', 'url'), ';');
                  foreach ($broken_user_list as $alias => $mails) {
                      $sel = Xdb::query(
                          "SELECT  u.user_id, count(e.email) AS nb_mails, u.nom, u.prenom, u.promo
                         GROUP BY  u.user_id", $alias);
  
                      if ($x = $sel->fetchOneAssoc()) {
+                         if ($x['nb_mails'] == 0) {
+                             register_profile_update($x['user_id'], 'broken');
+                         }
                          fputcsv($csv, array($x['nom'], $x['prenom'], $x['promo'], $alias,
-                                             join(',', $mails), $x['nb_mails']),
-                                             'https://www.polytechnique.org/marketing/broken/' . $alias, ';');
+                                             join(',', $mails), $x['nb_mails'],
+                                             'https://www.polytechnique.org/marketing/broken/' . $alias), ';');
                      }
                  }
                  fclose($csv);
diff --combined modules/events.php
@@@ -149,17 -149,16 +149,17 @@@ class EventsModule extends PLModul
  
          // Fetch the events to display, along with their metadata.
          $array = array();
 -        $it = XDB::iterator("SELECT  e.id,e.titre,e.texte,e.post_id,a.user_id,a.nom,a.prenom,a.promo,a.hruid,
 +        $it = XDB::iterator("SELECT  e.id, e.titre, e.texte, e.post_id, a.user_id, a.nom, a.prenom, d.promo AS promo_display ,a.hruid,
                                       p.x, p.y, p.attach IS NOT NULL AS img, FIND_IN_SET('wiki', e.flags) AS wiki,
                                       FIND_IN_SET('important', e.flags) AS important,
                                       e.creation_date > DATE_SUB(CURDATE(), INTERVAL 2 DAY) AS news,
                                       e.peremption < DATE_ADD(CURDATE(), INTERVAL 2 DAY) AS end,
                                       ev.user_id IS NULL AS nonlu
                                 FROM  evenements       AS e
 -                          LEFT JOIN  evenements_photo AS p ON (e.id = p.eid)
 -                         INNER JOIN  auth_user_md5    AS a ON e.user_id=a.user_id
 -                          LEFT JOIN  evenements_vus AS ev ON (e.id = ev.evt_id AND ev.user_id = {?})
 +                          LEFT JOIN  evenements_photo AS p  ON (e.id = p.eid)
 +                         INNER JOIN  auth_user_md5    AS a  ON (e.user_id = a.user_id)
 +                         INNER JOIN  profile_display  AS d  ON (d.pid = a.user_id)
 +                          LEFT JOIN  evenements_vus   AS ev ON (e.id = ev.evt_id AND ev.user_id = {?})
                                WHERE  FIND_IN_SET('valide', e.flags) AND peremption >= NOW()
                                       AND (e.promo_min = 0 || e.promo_min <= {?})
                                       AND (e.promo_max = 0 || e.promo_max >= {?})
              $res = XDB::query("SELECT * FROM evenements_photo WHERE eid = {?}", $eid);
              if ($res->numRows()) {
                  $photo = $res->fetchOneAssoc();
-                 header('Content-Type: image/' . $photo['attachmime']);
+                 pl_cached_dynamic_content_headers("image/" . $photo['attachmime']);
                  echo $photo['attach'];
                  exit;
              }
              require_once 'validations.inc.php';
              $valid = Validate::get_request_by_id($valid);
              if ($valid && $valid->img) {
-                 header('Content-Type: image/' . $valid->imgtype);
+                 pl_cached_dynamic_content_headers("image/" . $valid->imgtype);
                  echo $valid->img;
                  exit;
              }
          } else {
              $upload = new PlUpload(S::user()->login(), 'event');
              if ($upload->exists() && $upload->isType('image')) {
-                 header('Content-Type: ' . $upload->contentType());
+                 pl_cached_dynamic_content_headers($upload->contentType());
                  echo $upload->getContents();
                  exit;
              }
          }
          global $globals;
-         header('Content-Type: image/png');
+         pl_cached_dynamic_content_headers("image/png");
          echo file_get_contents($globals->spoolroot . '/htdocs/images/logo.png');
          exit;
      }
          }
          $page->assign('texte', $texte);
          $page->assign('titre', $titre);
-         header('Content-Type: text/html; charset=utf-8');
+         pl_content_headers("text/html");
      }
  
      function handler_ev_submit(&$page)
  
      function handler_tips(&$page, $tips = null)
      {
-         header('Content-Type: text/html; charset="UTF-8"');
+         pl_content_headers("text/html");
          $page->changeTpl('include/tips.tpl', NO_SKIN);
          $page->assign('tips', $this->get_tips($tips));
      }
diff --combined modules/newsletter.php
@@@ -151,25 -151,23 +151,26 @@@ class NewsletterModule extends PLModul
  
          if ($action == 'edit' && $aid != 'update') {
              $eaid = $aid;
 -            if(Post::has('title')) {
 +            if (Post::has('title')) {
                  $art  = new NLArticle(Post::v('title'), Post::v('body'), Post::v('append'),
                                        $eaid, Post::v('cid'), Post::v('pos'));
              } else {
                  $art = ($eaid == 'new') ? new NLArticle() : $nl->getArt($eaid);
              }
 +            if ($art && !$art->check()) {
 +                $page->trigError("Cet article est trop long.");
 +            }
              $page->assign('art', $art);
          }
  
          if ($aid == 'blacklist_check') {
+             global $globals;
              $ips_to_check = array();
-             $gethostbyname_count = 0;
+             $blacklist_host_resolution_count = 0;
  
              foreach ($nl->_arts as $key => $articles) {
                  foreach ($articles as $article) {
-                     $article_ips = $article->getLinkIps($gethostbyname_count);
+                     $article_ips = $article->getLinkIps($blacklist_host_resolution_count);
                      if (!empty($article_ips)) {
                          $ips_to_check[$article->title()] = $article_ips;
                      }
              }
  
              $page->assign('ips_to_check', $ips_to_check);
-             if ($gethostbyname_count >= $globals->mail->blacklist_host_resolution_limit) {
-                 $page-trigError("Toutes les url et adresses emails de la lettre"
+             if ($blacklist_host_resolution_count >= $globals->mail->blacklist_host_resolution_limit) {
+                 $page->trigError("Toutes les url et adresses emails de la lettre"
                                  . " n'ont pas été prises en compte car la"
                                  . " limite du nombre de résolutions DNS"
                                  . " autorisée a été atteinte.");
diff --combined modules/profile.php
@@@ -24,55 -24,45 +24,55 @@@ class ProfileModule extends PLModul
      function handlers()
      {
          return array(
 -            'photo'                => $this->make_hook('photo',             AUTH_PUBLIC),
 -            'photo/change'         => $this->make_hook('photo_change',      AUTH_MDP),
 -
 -            'fiche.php'            => $this->make_hook('fiche',             AUTH_PUBLIC),
 -            'profile'              => $this->make_hook('profile',           AUTH_PUBLIC),
 -            'profile/private'      => $this->make_hook('profile',           AUTH_COOKIE),
 -            'profile/ax'           => $this->make_hook('ax',                AUTH_COOKIE, 'admin'),
 -            'profile/edit'         => $this->make_hook('p_edit',            AUTH_MDP),
 -            'profile/ajax/address' => $this->make_hook('ajax_address',      AUTH_COOKIE, 'user', NO_AUTH),
 -            'profile/ajax/tel'     => $this->make_hook('ajax_tel',          AUTH_COOKIE, 'user', NO_AUTH),
 -            'profile/ajax/medal'   => $this->make_hook('ajax_medal',        AUTH_COOKIE, 'user', NO_AUTH),
 -            'profile/ajax/job'     => $this->make_hook('ajax_job',          AUTH_COOKIE, 'user', NO_AUTH),
 -            'profile/ajax/secteur' => $this->make_hook('ajax_secteur',      AUTH_COOKIE, 'user', NO_AUTH),
 -            'profile/ajax/skill'   => $this->make_hook('ajax_skill',        AUTH_COOKIE, 'user', NO_AUTH),
 -            'javascript/applis.js' => $this->make_hook('applis_js',         AUTH_COOKIE),
 -            'javascript/grades.js' => $this->make_hook('grades_js',         AUTH_COOKIE),
 -            'profile/medal'        => $this->make_hook('medal',             AUTH_PUBLIC),
 -            'profile/orange'       => $this->make_hook('p_orange',          AUTH_MDP),
 -            'profile/usage'        => $this->make_hook('p_usage',           AUTH_MDP),
 -
 -            'referent'             => $this->make_hook('referent',          AUTH_COOKIE),
 -            'emploi'               => $this->make_hook('ref_search',        AUTH_COOKIE),
 -            'referent/search'      => $this->make_hook('ref_search',        AUTH_COOKIE),
 -            'referent/ssect'       => $this->make_hook('ref_sect',          AUTH_COOKIE, 'user', NO_AUTH),
 -            'referent/country'     => $this->make_hook('ref_country',       AUTH_COOKIE, 'user', NO_AUTH),
 -
 -            'groupes-x'            => $this->make_hook('xnet',              AUTH_COOKIE),
 -            'groupes-x/logo'       => $this->make_hook('xnetlogo',          AUTH_PUBLIC),
 -
 -            'vcard'                => $this->make_hook('vcard',             AUTH_COOKIE),
 -            'admin/binets'         => $this->make_hook('admin_binets',      AUTH_MDP,    'admin'),
 -            'admin/medals'         => $this->make_hook('admin_medals',      AUTH_MDP,    'admin'),
 -            'admin/formations'     => $this->make_hook('admin_formations',  AUTH_MDP,    'admin'),
 -            'admin/sections'       => $this->make_hook('admin_sections',    AUTH_MDP,    'admin'),
 -            'admin/secteurs'       => $this->make_hook('admin_secteurs',    AUTH_MDP,    'admin'),
 -            'admin/trombino'       => $this->make_hook('admin_trombino',    AUTH_MDP,    'admin'),
 -            'admin/ss_secteurs'    => $this->make_hook('admin_ss_secteurs', AUTH_MDP,    'admin'),
 -            'admin/fonctions'      => $this->make_hook('admin_fonctions',   AUTH_MDP,    'admin'),
 -
 +            'photo'                      => $this->make_hook('photo',                      AUTH_PUBLIC),
 +            'photo/change'               => $this->make_hook('photo_change',               AUTH_MDP),
 +
 +            'fiche.php'                  => $this->make_hook('fiche',                      AUTH_PUBLIC),
 +            'profile'                    => $this->make_hook('profile',                    AUTH_PUBLIC),
 +            'profile/private'            => $this->make_hook('profile',                    AUTH_COOKIE),
 +            'profile/ax'                 => $this->make_hook('ax',                         AUTH_COOKIE, 'admin'),
 +            'profile/edit'               => $this->make_hook('p_edit',                     AUTH_MDP),
 +            'profile/ajax/address'       => $this->make_hook('ajax_address',               AUTH_COOKIE, 'user', NO_AUTH),
 +            'profile/ajax/tel'           => $this->make_hook('ajax_tel',                   AUTH_COOKIE, 'user', NO_AUTH),
 +            'profile/ajax/edu'           => $this->make_hook('ajax_edu',                   AUTH_COOKIE, 'user', NO_AUTH),
 +            'profile/ajax/medal'         => $this->make_hook('ajax_medal',                 AUTH_COOKIE, 'user', NO_AUTH),
 +            'profile/networking'         => $this->make_hook('networking',                 AUTH_PUBLIC),
 +            'profile/ajax/job'           => $this->make_hook('ajax_job',                   AUTH_COOKIE, 'user', NO_AUTH),
 +            'profile/ajax/sector'        => $this->make_hook('ajax_sector',                AUTH_COOKIE, 'user', NO_AUTH),
 +            'profile/ajax/sub_sector'    => $this->make_hook('ajax_sub_sector',            AUTH_COOKIE, 'user', NO_AUTH),
 +            'profile/ajax/alternates'    => $this->make_hook('ajax_alternates',            AUTH_COOKIE, 'user', NO_AUTH),
 +            'profile/ajax/skill'         => $this->make_hook('ajax_skill',                 AUTH_COOKIE, 'user', NO_AUTH),
 +            'profile/ajax/searchname'    => $this->make_hook('ajax_searchname',            AUTH_COOKIE, 'user', NO_AUTH),
 +            'profile/ajax/buildnames'    => $this->make_hook('ajax_buildnames',            AUTH_COOKIE, 'user', NO_AUTH),
 +            'javascript/education.js'    => $this->make_hook('education_js',               AUTH_COOKIE),
 +            'javascript/grades.js'       => $this->make_hook('grades_js',                  AUTH_COOKIE),
 +            'profile/medal'              => $this->make_hook('medal',                      AUTH_PUBLIC),
 +            'profile/name_info'          => $this->make_hook('name_info',                  AUTH_PUBLIC),
 +            'profile/orange'             => $this->make_hook('p_orange',                   AUTH_MDP),
 +
 +            'referent'                   => $this->make_hook('referent',                   AUTH_COOKIE),
 +            'emploi'                     => $this->make_hook('ref_search',                 AUTH_COOKIE),
 +            'referent/search'            => $this->make_hook('ref_search',                 AUTH_COOKIE),
 +            'referent/ssect'             => $this->make_hook('ref_sect',                   AUTH_COOKIE, 'user', NO_AUTH),
 +            'referent/country'           => $this->make_hook('ref_country',                AUTH_COOKIE, 'user', NO_AUTH),
 +
 +            'groupes-x'                  => $this->make_hook('xnet',                       AUTH_COOKIE),
 +            'groupes-x/logo'             => $this->make_hook('xnetlogo',                   AUTH_PUBLIC),
 +
 +            'vcard'                      => $this->make_hook('vcard',                      AUTH_COOKIE, 'user', NO_HTTPS),
 +            'admin/binets'               => $this->make_hook('admin_binets',               AUTH_MDP, 'admin'),
 +            'admin/medals'               => $this->make_hook('admin_medals',               AUTH_MDP, 'admin'),
 +            'admin/education'            => $this->make_hook('admin_education',            AUTH_MDP, 'admin'),
 +            'admin/education_field'      => $this->make_hook('admin_education_field',      AUTH_MDP, 'admin'),
 +            'admin/education_degree'     => $this->make_hook('admin_education_degree',     AUTH_MDP, 'admin'),
 +            'admin/education_degree_set' => $this->make_hook('admin_education_degree_set', AUTH_MDP, 'admin'),
 +            'admin/sections'             => $this->make_hook('admin_sections',             AUTH_MDP, 'admin'),
 +            'admin/networking'           => $this->make_hook('admin_networking',           AUTH_MDP, 'admin'),
 +            'admin/trombino'             => $this->make_hook('admin_trombino',             AUTH_MDP, 'admin'),
 +            'admin/sectors'              => $this->make_hook('admin_sectors',              AUTH_MDP, 'admin'),
 +            'admin/corps_enum'           => $this->make_hook('admin_corps_enum',           AUTH_MDP, 'admin'),
 +            'admin/corps_rank'           => $this->make_hook('admin_corps_rank',           AUTH_MDP, 'admin'),
 +            'admin/names'                => $this->make_hook('admin_names',                AUTH_MDP, 'admin'),
          );
      }
  
  
          // Display the photo, or a default one when not available.
          if ($photo_type && $photo_data != null) {
-             header('Content-type: image/' . $photo_type);
+             pl_cached_dynamic_content_headers("image/$photo_type");
              echo $photo_data;
          } else {
-             header('Content-type: image/png');
+             pl_cached_dynamic_content_headers("image/png");
              echo file_get_contents(dirname(__FILE__).'/../htdocs/images/none.png');
          }
          exit;
          $img  = $thumb ?
              dirname(__FILE__).'/../htdocs/images/medals/thumb/' . $res->fetchOneCell() :
              dirname(__FILE__).'/../htdocs/images/medals/' . $res->fetchOneCell();
-         $type = mime_content_type($img);
-         header("Content-Type: $type");
+         pl_cached_content_headers(mime_content_type($img));
          echo file_get_contents($img);
          exit;
      }
  
 +    function handler_name_info(&$page)
 +    {
 +        header('Content-Type: text/html; charset=utf-8');
 +        $page->changeTpl('profile/name_info.tpl', SIMPLE);
 +        $res = XDB::iterator("SELECT  name, explanations,
 +                                      FIND_IN_SET('public', flags) AS public,
 +                                      FIND_IN_SET('has_particle', flags) AS has_particle
 +                                FROM  profile_name_enum
 +                               WHERE  NOT FIND_IN_SET('not_displayed', flags)
 +                            ORDER BY  NOT FIND_IN_SET('public', flags)");
 +        $page->assign('types', $res);
 +    }
 +
 +    function handler_networking(&$page, $mid)
 +    {
 +        $res = XDB::query("SELECT  icon
 +                             FROM  profile_networking_enum
 +                            WHERE  network_type = {?}",
 +                          $mid);
 +        $img  = dirname(__FILE__) . '/../htdocs/images/networking/' . $res->fetchOneCell();
 +        $type = mime_content_type($img);
 +        header("Content-Type: $type");
 +        echo file_get_contents($img);
 +        exit;
 +    }
 +
      function handler_photo_change(&$page)
      {
          global $globals;
  
          // Build the page
          $page->addJsLink('ajax.js');
 -        $page->addJsLink('applis.js');
 +        $page->addJsLink('education.js');
          $page->addJsLink('grades.js');
          $page->addJsLink('profile.js');
          $page->addJsLink('jquery.autocomplete.js');
         }
      }
  
 -    function handler_applis_js(&$page)
 +    function handler_education_js(&$page)
      {
-         header('Content-Type: text/javascript; charset=utf-8');
-         header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
-         header('Last-Modified:' . gmdate('D, d M Y H:i:s') . ' GMT');
-         header('Cache-Control: no-cache, must-revalidate');
-         header('Pragma: no-cache');
+         pl_cached_content_headers("text/javascript", "utf-8");
 -        $page->changeTpl('profile/applis.js.tpl', NO_SKIN);
 -        require_once "applis.func.inc.php";
 +        $page->changeTpl('profile/education.js.tpl', NO_SKIN);
-         require_once "education.func.inc.php";
++        require_once 'education.func.inc.php';
      }
  
      function handler_grades_js(&$page)
      {
-         header('Content-Type: text/javascript; charset=utf-8');
-         header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
-         header('Last-Modified:' . gmdate('D, d M Y H:i:s') . ' GMT');
-         header('Cache-Control: no-cache, must-revalidate');
-         header('Pragma: no-cache');
+         pl_cached_content_headers("text/javascript", "utf-8");
          $page->changeTpl('profile/grades.js.tpl', NO_SKIN);
          $res    = XDB::iterator("SELECT  *
                                     FROM  profile_medals_grades
          $page->assign('medal_list', $mlist);
      }
  
 -    function handler_ajax_address(&$page, $adid)
 +    function handler_ajax_address(&$page, $id)
      {
-         header('Content-Type: text/html; charset=utf-8');
+         pl_content_headers("text/html");
          $page->changeTpl('profile/adresses.address.tpl', NO_SKIN);
 -        $page->assign('i', $adid);
 -        $page->assign('adr', array());
 +        $page->assign('i', $id);
 +        $page->assign('address', array());
      }
  
 -    function handler_ajax_tel(&$page, $adid, $telid)
 +    function handler_ajax_tel(&$page, $prefid, $prefname, $telid)
      {
-         header('Content-Type: text/html; charset=utf-8');
+         pl_content_headers("text/html");
 -        $page->changeTpl('profile/adresses.tel.tpl', NO_SKIN);
 -        $page->assign('i', $adid);
 -        $page->assign('adid', "addresses_$adid");
 -        $page->assign('adpref', "addresses[$adid]");
 -        $page->assign('t', $telid);
 +        $page->changeTpl('profile/phone.tpl', NO_SKIN);
 +        $page->assign('prefid', $prefid);
 +        $page->assign('prefname', $prefname);
 +        $page->assign('telid', $telid);
          $page->assign('tel', array());
      }
  
 +    function handler_ajax_edu(&$page, $eduid, $class)
 +    {
 +        header('Content-Type: text/html; charset=utf-8');
 +        $page->changeTpl('profile/general.edu.tpl', NO_SKIN);
 +        $res = XDB::iterator("SELECT  id, field
 +                                FROM  profile_education_field_enum
 +                            ORDER BY  field");
 +        $page->assign('edu_fields', $res->fetchAllAssoc());
 +        $page->assign('eduid', $eduid);
 +        $page->assign('class', $class);
 +        require_once "education.func.inc.php";
 +    }
 +
      function handler_ajax_medal(&$page, $id)
      {
-         header('Content-Type: text/html; charset=utf-8');
+         pl_content_headers("text/html");
          $page->changeTpl('profile/deco.medal.tpl', NO_SKIN);
          $page->assign('id', $id);
          $page->assign('medal', array('valid' => 0, 'grade' => 0));
  
      function handler_ajax_job(&$page, $id)
      {
-         header('Content-Type: text/html; charset=utf-8');
+         pl_content_headers("text/html");
          $page->changeTpl('profile/jobs.job.tpl', NO_SKIN);
          $page->assign('i', $id);
          $page->assign('job', array());
          $page->assign('new', true);
 -        $res = XDB::query("SELECT  id, label
 -                             FROM  emploi_secteur");
 -        $page->assign('secteurs', $res->fetchAllAssoc());
 -        $res = XDB::query("SELECT  id, fonction_fr, FIND_IN_SET('titre', flags) AS title
 -                             FROM  fonctions_def
 -                         ORDER BY  id");
 -        $page->assign('fonctions', $res->fetchAllAssoc());
 +        $res = XDB::query("SELECT  id, name AS label
 +                             FROM  profile_job_sector_enum");
 +        $page->assign('sectors', $res->fetchAllAssoc());
 +        require_once "emails.combobox.inc.php";
 +        fill_email_combobox($page);
      }
  
 -    function handler_ajax_secteur(&$page, $id, $sect, $ssect = -1)
 +    function handler_ajax_sector(&$page, $id, $jobid, $jobpref, $sect, $ssect = -1)
      {
-         header('Content-Type: text/html; charset=utf-8');
+         pl_content_headers("text/html");
 -        $res = XDB::iterator("SELECT  id, label
 -                                FROM  emploi_ss_secteur
 -                               WHERE  secteur = {?}", $sect);
 -        $page->changeTpl('profile/jobs.secteur.tpl', NO_SKIN);
 +        $res = XDB::iterator("SELECT  id, name, FIND_IN_SET('optgroup', flags) AS optgroup
 +                                FROM  profile_job_subsector_enum
 +                               WHERE  sectorid = {?}", $sect);
 +        $page->changeTpl('profile/jobs.sector.tpl', NO_SKIN);
          $page->assign('id', $id);
 -        $page->assign('ssecteurs', $res);
 +        $page->assign('subSectors', $res);
          $page->assign('sel', $ssect);
 +        if ($id != -1) {
 +            $page->assign('change', 1);
 +            $page->assign('jobid', $jobid);
 +            $page->assign('jobpref', $jobpref);
 +        }
 +    }
 +
 +    function handler_ajax_sub_sector(&$page, $id, $ssect, $sssect = -1)
 +    {
 +        header('Content-Type: text/html; charset=utf-8');
 +        $res = XDB::iterator("SELECT  id, name
 +                                FROM  profile_job_subsubsector_enum
 +                               WHERE  subsectorid = {?}", $ssect);
 +        $page->changeTpl('profile/jobs.sub_sector.tpl', NO_SKIN);
 +        $page->assign('id', $id);
 +        $page->assign('subSubSectors', $res);
 +        $page->assign('sel', $sssect);
 +    }
 +
 +    function handler_ajax_alternates(&$page, $id, $sssect)
 +    {
 +        header('Content-Type: text/html; charset=utf-8');
 +        $res = XDB::iterator('SELECT  name
 +                                FROM  profile_job_alternates
 +                               WHERE  subsubsectorid = {?}
 +                            ORDER BY  id',
 +                             $sssect);
 +        $page->changeTpl('profile/jobs.alternates.tpl', NO_SKIN);
 +        $alternate  = $res->next();
 +        $alternates = $alternate['name'];
 +        while ($alternate  = $res->next()) {
 +            $alternates .= ', ' . $alternate['name'];
 +        }
 +        $page->assign('alternates', $alternates);
      }
  
      function handler_ajax_skill(&$page, $cat, $id)
      {
-         header('Content-Type: text/html; charset=utf-8');
+         pl_content_headers("text/html");
          $page->changeTpl('profile/skill.skill.tpl', NO_SKIN);
          $page->assign('cat', $cat);
          $page->assign('id', $id);
          }
      }
  
 +    function handler_ajax_searchname(&$page, $id)
 +    {
 +        header('Content-Type: text/html; charset=utf-8');
 +        $page->changeTpl('profile/general.searchname.tpl', NO_SKIN);
 +        $res = XDB::query("SELECT  id, name, FIND_IN_SET('public', flags) AS pub
 +                             FROM  profile_name_enum
 +                            WHERE  NOT FIND_IN_SET('not_displayed', flags)
 +                                   AND NOT FIND_IN_SET('always_displayed', flags)");
 +        $page->assign('sn_type_list', $res->fetchAllAssoc());
 +        $page->assign('i', $id);
 +    }
 +
 +    function handler_ajax_buildnames(&$page, $data)
 +    {
 +        header('Content-Type: text/html; charset=utf-8');
 +        $page->changeTpl('profile/general.buildnames.tpl', NO_SKIN);
 +        require_once 'name.func.inc.php';
 +        $page->assign('names', build_javascript_names($data));
 +    }
 +
      function handler_p_orange(&$page)
      {
          $page->changeTpl('profile/orange.tpl');
  
          require_once 'validations.inc.php';
  
 -        $res = XDB::query(
 -                "SELECT  u.promo, u.promo_sortie
 -                   FROM  auth_user_md5  AS u
 -                  WHERE  user_id={?}", S::v('uid'));
 +        $res = XDB::query("SELECT  e.entry_year, e.grad_year, d.promo, FIND_IN_SET('femme', u.flags) AS sexe
 +                             FROM  auth_user_md5     AS u
 +                       INNER JOIN  profile_display   AS d ON (d.pid = u.user_id)
 +                       INNER JOIN  profile_education AS e ON (e.uid = u.user_id AND FIND_IN_SET('primary', e.flags))
 +                            WHERE  u.user_id = {?}", S::v('uid'));
  
 -        list($promo, $promo_sortie_old) = $res->fetchOneRow();
 +        list($promo, $promo_sortie_old, $promo_display, $sexe) = $res->fetchOneRow();
          $page->assign('promo_sortie_old', $promo_sortie_old);
 -        $page->assign('promo',  $promo);
 +        $page->assign('promo', $promo);
 +        $page->assign('promo_display', $promo_display);
 +        $page->assign('sexe', $sexe);
  
          if (!Env::has('promo_sortie')) {
              return;
          $promo_sortie = Env::i('promo_sortie');
  
          if ($promo_sortie < 1000 || $promo_sortie > 9999) {
 -            $page->trigError('L\'année de sortie doit être un nombre de quatre chiffres');
 +            $page->trigError('L\'année de sortie doit être un nombre de quatre chiffres.');
          }
          elseif ($promo_sortie < $promo + 3) {
 -            $page->trigError('Trop tôt');
 +            $page->trigError('Trop tôt !');
          }
          elseif ($promo_sortie == $promo_sortie_old) {
              $page->trigWarning('Tu appartiens déjà à la promotion correspondante à cette année de sortie.');
          }
          elseif ($promo_sortie == $promo + 3) {
 -            XDB::execute(
 -                "UPDATE  auth_user_md5 set promo_sortie={?}
 -                  WHERE  user_id={?}", $promo_sortie, S::v('uid'));
 +            XDB::execute("UPDATE  profile_education
 +                             SET  grad_year = {?}
 +                           WHERE  uid = {?} AND FIND_IN_SET('primary', flags)", $promo_sortie, S::v('uid'));
                  $page->trigSuccess('Ton statut "orange" a été supprimé.');
                  $page->assign('promo_sortie_old', $promo_sortie);
          }
          /////  recuperations infos referent
  
          //expertise
 -        $res = XDB::query("SELECT expertise FROM mentor WHERE uid = {?}", $user->id());
 +        $res = XDB::query("SELECT expertise FROM profile_mentor WHERE uid = {?}", $user->id());
          $page->assign('expertise', $res->fetchOneCell());
  
 -        //secteurs
 -        $secteurs = $ss_secteurs = Array();
 +        // Sectors
 +        $sectors = $subSectors = Array();
          $res = XDB::iterRow(
 -                "SELECT  s.label, ss.label
 -                   FROM  mentor_secteurs AS m
 -              LEFT JOIN  emploi_secteur AS s ON(m.secteur = s.id)
 -              LEFT JOIN  emploi_ss_secteur AS ss ON(m.secteur = ss.secteur AND m.ss_secteur = ss.id)
 +                "SELECT  s.name AS label, ss.name AS label
 +                   FROM  profile_mentor_sector      AS m
 +              LEFT JOIN  profile_job_sector_enum    AS s  ON(m.sectorid = s.id)
 +              LEFT JOIN  profile_job_subsector_enum AS ss ON(m.sectorid = ss.sectorid AND m.subsectorid = ss.id)
                    WHERE  uid = {?}", $user->id());
 -        while (list($sec, $ssec) = $res->next()) {
 -            $secteurs[]    = $sec;
 -            $ss_secteurs[] = $ssec;
 +        while (list($sector, $subSector) = $res->next()) {
 +            $sectors[]    = $sector;
 +            $subSectors[] = $subSector;
          }
 -        $page->assign_by_ref('secteurs', $secteurs);
 -        $page->assign_by_ref('ss_secteurs', $ss_secteurs);
 +        $page->assign_by_ref('sectors', $sectors);
 +        $page->assign_by_ref('subSectors', $subSectors);
  
 -        //pays
 +        // Countries.
          $res = XDB::query(
 -                "SELECT  gp.pays
 -                   FROM  mentor_pays AS m
 -              LEFT JOIN  geoloc_pays AS gp ON(m.pid = gp.a2)
 +                "SELECT  gc.countryFR
 +                   FROM  profile_mentor_country AS m
 +              LEFT JOIN  geoloc_countries       AS gc ON (m.country = gc.iso_3166_1_a2)
                    WHERE  uid = {?}", $user->id());
          $page->assign('pays', $res->fetchColumn());
  
  
          $page->setTitle('Conseil Pro');
  
 -        //recuperation des noms de secteurs
 -        $res = XDB::iterRow("SELECT id, label FROM emploi_secteur");
 -        $secteurs[''] = '';
 +        // Retrieval of sector names
 +        $res = XDB::iterRow("SELECT  id, name AS label
 +                               FROM  profile_job_sector_enum");
 +        $sectors[''] = '';
          while (list($tmp_id, $tmp_label) = $res->next()) {
 -            $secteurs[$tmp_id] = $tmp_label;
 +            $sectors[$tmp_id] = $tmp_label;
          }
 -        $page->assign_by_ref('secteurs', $secteurs);
 +        $page->assign_by_ref('sectors', $sectors);
  
          // nb de mentors
 -        $res = XDB::query("SELECT count(*) FROM mentor");
 +        $res = XDB::query("SELECT count(*) FROM profile_mentor");
          $page->assign('mentors_number', $res->fetchOneCell());
  
          // On vient d'un formulaire
 -        $where           = array();
 -        $pays_sel        = XDB::escape(Env::v('pays_sel'));
 -        $secteur_sel     = XDB::escape(Env::v('secteur'));
 -        $ss_secteur_sel  = XDB::escape(Env::v('ss_secteur'));
 -        $expertise_champ = XDB::escape(Env::v('expertise'));
 +        $where              = array();
 +        $pays_sel           = XDB::escape(Env::v('pays_sel'));
 +        $sectorSelection    = XDB::escape(Env::v('sector'));
 +        $subSectorSelection = XDB::escape(Env::v('subSector'));
 +        $expertise_champ    = XDB::escape(Env::v('expertise'));
  
          if ($pays_sel != "''") {
 -            $where[] = "mp.pid = $pays_sel";
 +            $where[] = "mp.country = $pays_sel";
          }
 -        if ($secteur_sel != "''") {
 -            $where[] = "ms.secteur = $secteur_sel";
 -            if ($ss_secteur_sel != "''") {
 -                $where[] = "ms.ss_secteur = $ss_secteur_sel";
 +        if ($sectorSelection != "''") {
 +            $where[] = "ms.sectorid = " . $sectorSelection;
 +            if ($selectedSubSector != "''") {
 +                $where[] = "ms.subsectorid = " . $subSectorSelection;
              }
          }
          if ($expertise_champ != "''") {
          if ($where) {
              $where = join(' AND ', $where);
  
 -            $set = new UserSet("INNER JOIN  mentor          AS m ON (m.uid = u.user_id)
 -                                 LEFT JOIN  mentor_pays     AS mp ON (mp.uid = m.uid)
 -                                 LEFT JOIN  mentor_secteurs AS ms ON (ms.uid = m.uid)",
 +            $set = new UserSet("INNER JOIN  profile_mentor          AS m  ON (m.uid = u.user_id)
 +                                 LEFT JOIN  profile_mentor_country  AS mp ON (mp.uid = m.uid)
 +                                 LEFT JOIN  profile_mentor_sector   AS ms ON (ms.uid = m.uid)",
                                 $where);
              $set->addMod('mentor', 'Référents');
              $set->apply('referent/search', $page, $action, $subaction);
  
      function handler_ref_sect(&$page, $sect)
      {
-         header('Content-Type: text/html; charset=utf-8');
+         pl_content_headers("text/html");
          $page->changeTpl('include/field.select.tpl', NO_SKIN);
 -        $page->assign('onchange', 'setSSecteurs()');
 +        $page->assign('onchange', 'setSSectors()');
          $page->assign('id', 'ssect_field');
 -        $page->assign('name', 'ss_secteur');
 -        $it = XDB::iterator("SELECT  id,label AS field
 -                               FROM  emploi_ss_secteur
 -                              WHERE  secteur = {?}", $sect);
 +        $page->assign('name', 'subSector');
 +        $it = XDB::iterator("SELECT  id, name AS field
 +                               FROM  profile_job_subsector_enum
 +                              WHERE  sectorid = {?}", $sect);
          $page->assign('list', $it);
      }
  
      function handler_ref_country(&$page, $sect, $ssect = '')
      {
-         header('Content-Type: text/html; charset=utf-8');
+         pl_content_headers("text/html");
          $page->changeTpl('include/field.select.tpl', NO_SKIN);
          $page->assign('name', 'pays_sel');
 -        $where = ($ssect ? ' AND ms.ss_secteur = {?}' : '');
 -        $it = XDB::iterator("SELECT  a2 AS id, pays AS field
 -                              FROM  geoloc_pays AS g
 -                        INNER JOIN  mentor_pays AS mp ON (mp.pid = g.a2)
 -                        INNER JOIN  mentor_secteurs AS ms ON (ms.uid = mp.uid)
 -                             WHERE  ms.secteur = {?} $where
 -                          GROUP BY  a2
 -                          ORDER BY  pays", $sect, $ssect);
 +        $where = ($ssect ? ' AND ms.subsectorid = {?}' : '');
 +        $it = XDB::iterator("SELECT  gc.iso_3166_1_a2 AS id, gc.countryFR AS field
 +                               FROM  geoloc_countries       AS gc
 +                         INNER JOIN  profile_mentor_country AS mp ON (mp.country = gc.iso_3166_1_a2)
 +                         INNER JOIN  profile_mentor_sector  AS ms ON (ms.uid = mp.uid)
 +                              WHERE  ms.sectorid = {?} " . $where . "
 +                           GROUP BY  iso_3166_1_a2
 +                           ORDER BY  countryFR", $sect, $ssect);
          $page->assign('list', $it);
      }
  
 -    function handler_p_usage(&$page)
 -    {
 -        $page->changeTpl('profile/nomusage.tpl');
 -
 -        require_once 'validations.inc.php';
 -
 -        $res = XDB::query(
 -                "SELECT  u.nom, u.nom_usage, u.flags, e.alias
 -                   FROM  auth_user_md5  AS u
 -              LEFT JOIN  aliases        AS e ON(u.user_id = e.id
 -                                                AND FIND_IN_SET('usage', e.flags))
 -                  WHERE  user_id={?}", S::v('uid'));
 -
 -        list($nom, $usage_old, $flags, $alias_old) = $res->fetchOneRow();
 -        $flags = new PlFlagSet($flags);
 -        $page->assign('usage_old', $usage_old);
 -        $page->assign('alias_old',  $alias_old);
 -
 -        $nom_usage = mb_strtoupper(trim(Env::v('nom_usage')));
 -        $page->assign('usage_req', $nom_usage);
 -
 -        if (Env::has('submit') && ($nom_usage != $usage_old)) {
 -            S::assert_xsrf_token();
 -
 -            // on vient de recevoir une requete, differente de l'ancien nom d'usage
 -            if ($nom_usage == $nom) {
 -                $page->trigWarning('Le nom d\'usage que tu demandes est identique à ton nom à l\'X, '
 -                                   . 'aucune modification n\'a donc été effectuée.');
 -                $page->assign('same', true);
 -            } else { // le nom de mariage est distinct du nom à l'X
 -                // on calcule l'alias pour l'afficher
 -                $reason = Env::v('reason');
 -                if ($reason == 'other') {
 -                    $reason = Env::v('other_reason');
 -                }
 -                $myusage = new UsageReq(S::user(), $nom_usage, $reason);
 -                $myusage->submit();
 -                $page->assign('myusage', $myusage);
 -            }
 -        }
 -    }
 -
      function handler_xnet(&$page)
      {
          $page->changeTpl('profile/groupesx.tpl');
          $req = XDB::query('
              SELECT m.asso_id, a.nom, diminutif, a.logo IS NOT NULL AS has_logo,
                     COUNT(e.eid) AS events, mail_domain AS lists
-               FROM groupex.membres AS m
-         INNER JOIN groupex.asso AS a ON(m.asso_id = a.id)
-          LEFT JOIN groupex.evenements AS e ON(e.asso_id = m.asso_id AND e.archive = 0)
+               FROM #groupex#.membres AS m
+         INNER JOIN #groupex#.asso AS a ON(m.asso_id = a.id)
+          LEFT JOIN #groupex#.evenements AS e ON(e.asso_id = m.asso_id AND e.archive = 0)
               WHERE uid = {?} GROUP BY m.asso_id ORDER BY a.nom', S::i('uid'));
          $page->assign('assos', $req->fetchAllAssoc());
      }
          }
  
          $res = XDB::query('SELECT  logo, logo_mime
-                              FROM  groupex.asso
+                              FROM  #groupex#.asso
                              WHERE  id = {?}', $id);
          list($logo, $logo_mime) = $res->fetchOneRow();
  
          if (!empty($logo)) {
-             header("Content-type: $mime");
+             pl_cached_dynamic_content_headers($logo_mime);
              echo $logo;
          } else {
-             header('Content-type: image/jpeg');
+             pl_cached_dynamic_content_headers("image/jpeg");
              readfile(dirname(__FILE__) . '/../htdocs/images/dflt_carre.jpg');
          }
  
  
          switch ($action) {
              case "original":
-                 header("Content-type: image/jpeg");
+                 pl_cached_content_headers("image/jpeg");
                readfile("/home/web/trombino/photos" . $user->promo() . "/" . $user->login() . ".jpg");
                  exit;
-               break;
  
              case "new":
                  S::assert_xsrf_token();
                  break;
          }
      }
 +    function handler_admin_names(&$page, $action = 'list', $id = null) {
 +        $page->setTitle('Administration - Types de noms');
 +        $page->assign('title', 'Gestion des types de noms');
 +        $table_editor = new PLTableEditor('admin/names', 'profile_name_enum', 'id', true);
 +        $table_editor->describe('name', 'Nom', true);
 +        $table_editor->describe('explanations', 'Explications', true);
 +        $table_editor->describe('type', 'Type', true);
 +        $table_editor->describe('flags', 'Flags', true);
 +        $table_editor->describe('score', 'Score', true);
 +        $table_editor->apply($page, $action, $id);
 +    }
      function handler_admin_binets(&$page, $action = 'list', $id = null) {
          $page->setTitle('Administration - Binets');
          $page->assign('title', 'Gestion des binets');
          $table_editor->describe('text','intitulé',true);
          $table_editor->apply($page, $action, $id);
      }
 -    function handler_admin_formations(&$page, $action = 'list', $id = null) {
 +    function handler_admin_education(&$page, $action = 'list', $id = null) {
          $page->setTitle('Administration - Formations');
          $page->assign('title', 'Gestion des formations');
 -        $table_editor = new PLTableEditor('admin/formations','applis_def','id');
 -        $table_editor->add_join_table('applis_ins','aid',true);
 -        $table_editor->describe('text','intitulé',true);
 -        $table_editor->describe('url','site web',false);
 +        $table_editor = new PLTableEditor('admin/education', 'profile_education_enum', 'id');
 +        $table_editor->add_join_table('profile_education', 'eduid', true);
 +        $table_editor->add_join_table('profile_education_degree', 'eduid', true);
 +        $table_editor->describe('name', 'intitulé', true);
 +        $table_editor->describe('url', 'site web', false);
 +        $table_editor->apply($page, $action, $id);
 +    }
 +    function handler_admin_education_field(&$page, $action = 'list', $id = null) {
 +        $page->setTitle('Administration - Domaines de formation');
 +        $page->assign('title', 'Gestion des domaines de formation');
 +        $table_editor = new PLTableEditor('admin/education_field', 'profile_education_field_enum', 'id', true);
 +        $table_editor->add_join_table('profile_education', 'fieldid', true);
 +        $table_editor->describe('field', 'domaine', true);
 +        $table_editor->apply($page, $action, $id);
 +    }
 +    function handler_admin_education_degree(&$page, $action = 'list', $id = null) {
 +        $page->setTitle('Administration - Niveau de formation');
 +        $page->assign('title', 'Gestion des niveau de formation');
 +        $table_editor = new PLTableEditor('admin/education_degree', 'profile_education_degree_enum', 'id', true);
 +        $table_editor->add_join_table('profile_education_degree', 'degreeid', true);
 +        $table_editor->add_join_table('profile_education', 'degreeid', true);
 +        $table_editor->describe('degree', 'niveau', true);
 +        $table_editor->apply($page, $action, $id);
 +    }
 +    function handler_admin_education_degree_set(&$page, $action = 'list', $id = null) {
 +        $page->setTitle('Administration - Correspondances formations - niveau de formation');
 +        $page->assign('title', 'Gestion des correspondances formations - niveau de formation');
 +        $table_editor = new PLTableEditor('admin/education_degree_set', 'profile_education_degree', 'eduid', true);
 +        $table_editor->describe('eduid', 'formation', true);
 +        $table_editor->describe('degreeid', 'niveau', true);
          $table_editor->apply($page, $action, $id);
      }
      function handler_admin_sections(&$page, $action = 'list', $id = null) {
          $table_editor->describe('text','intitulé',true);
          $table_editor->apply($page, $action, $id);
      }
 -    function handler_admin_ss_secteurs(&$page, $action = 'list', $id = null) {
 -        $page->setTitle('Administration - Sous-secteurs');
 -        $page->assign('title', 'Gestion des sous-secteurs');
 -        $table_editor = new PLTableEditor('admin/ss_secteurs', 'emploi_ss_secteur', 'id', true);
 -        $table_editor->describe('label', 'intitulé', true);
 +    function handler_admin_sectors(&$page, $action = 'list', $id = null) {
 +        $page->setTitle('Administration - Secteurs');
 +        $page->assign('title', 'Gestion des secteurs');
 +        $table_editor = new PLTableEditor('admin/sectors', 'profile_job_subsubsector_enum', 'id', true);
 +        $table_editor->describe('sectorid', 'id du secteur', false);
 +        $table_editor->describe('subsectorid', 'id du sous-secteur', false);
 +        $table_editor->describe('name', 'nom', true);
 +        $table_editor->describe('flags', 'affichage', true);
          $table_editor->apply($page, $action, $id);
      }
 -    function handler_admin_fonctions(&$page, $action = 'list', $id = null) {
 -        $page->setTitle('Administration - Fonctions');
 -        $page->assign('title', 'Gestion des fonctions');
 -        $table_editor = new PLTableEditor('admin/fonctions', 'fonctions_def', 'id', true);
 -        $table_editor->describe('fonction_fr', 'intitulé', true);
 -        $table_editor->describe('fonction_en', 'intitulé (ang)', true);
 -        $table_editor->describe('flags', 'titre', true);
 +    function handler_admin_networking(&$page, $action = 'list', $id = null) {
 +        $page->assign('xorg_title', 'Polytechnique.org - Administration - Networking');
 +        $page->assign('title', 'Gestion des types de networking');
 +        $table_editor = new PLTableEditor('admin/networking', 'profile_networking_enum', 'network_type');
 +        $table_editor->describe('name', 'intitulé', true);
 +        $table_editor->describe('icon', 'nom de l\'icône', false);
 +        $table_editor->describe('filter', 'filtre', true);
 +        $table_editor->describe('link', 'lien web', true);
          $table_editor->apply($page, $action, $id);
      }
 -    function handler_admin_secteurs(&$page, $action = 'list', $id = null) {
 -        $page->setTitle('Administration - Secteurs');
 -        $page->assign('title', 'Gestion des secteurs');
 -        $table_editor = new PLTableEditor('admin/secteurs', 'emploi_secteur', 'id', true);
 -        $table_editor->describe('label', 'intitulé', true);
 +    function handler_admin_corps_enum(&$page, $action = 'list', $id = null) {
 +        $page->setTitle('Administration - Corps');
 +        $page->assign('title', 'Gestion des Corps');
 +        $table_editor = new PLTableEditor('admin/corps_enum', 'profile_corps_enum', 'id');
 +        $table_editor->describe('name', 'intitulé', true);
 +        $table_editor->describe('abbreviation', 'abbréviation', true);
 +        $table_editor->describe('still_exists', 'existe encore ?', true);
 +        $table_editor->apply($page, $action, $id);
 +    }
 +    function handler_admin_corps_rank(&$page, $action = 'list', $id = null) {
 +        $page->setTitle('Administration - Grade dans les Corps');
 +        $page->assign('title', 'Gestion des grade dans les Corps');
 +        $table_editor = new PLTableEditor('admin/corps_rank', 'profile_corps_rank_enum', 'id');
 +        $table_editor->describe('name', 'intitulé', true);
 +        $table_editor->describe('abbreviation', 'abbréviation', true);
          $table_editor->apply($page, $action, $id);
      }
      function handler_admin_medals(&$page, $action = 'list', $id = null) {
diff --combined modules/register.php
@@@ -348,10 -348,10 +348,10 @@@ class RegisterModule extends PLModul
                      $storage->activate();
                      break;
                  case 'ml_promo':
-                     $r = XDB::query('SELECT id FROM groupex.asso WHERE diminutif = {?}', S::user()->promo());
+                     $r = XDB::query('SELECT id FROM #groupex#.asso WHERE diminutif = {?}', S::user()->promo());
                      if ($r->numRows()) {
                          $asso_id = $r->fetchOneCell();
-                         XDB::execute('REPLACE INTO  groupex.membres (uid, asso_id)
+                         XDB::execute('REPLACE INTO  #groupex#.membres (uid, asso_id)
                                              VALUES  ({?}, {?})',
                                       S::user()->id(), $asso_id);
                          $mmlist = new MMList(S::user()->id(), S::v('password'));
          $promo_forum = 'xorg.promo.x' . $promo;
          $registered_forums = array('xorg.general', 'xorg.pa.divers', 'xorg.pa.logements', $promo_forum);
          foreach ($registered_forums as $forum) {
-             XDB::execute("INSERT INTO  forums.abos (fid,uid)
+             XDB::execute("INSERT INTO  #forums#.abos (fid,uid)
                                 SELECT  fid, {?}
-                                  FROM   forums.list
+                                  FROM  #forums#.list
                                  WHERE  nom = {?}",
                                  $uid, $val);
  
          $res = XDB::iterRow(
                  "SELECT  sa.alias, IF(s.nom_usage,s.nom_usage,s.nom) AS nom,
                           s.prenom, FIND_IN_SET('femme', s.flags) AS femme,
 -                         GROUP_CONCAT(m.email) AS mails, MAX(m.last) AS dateDernier
 +                         GROUP_CONCAT(m.email SEPARATOR ', ') AS mails, MAX(m.last) AS dateDernier
                     FROM  register_marketing AS m
               INNER JOIN  auth_user_md5      AS s  ON (m.sender = s.user_id)
               INNER JOIN  aliases            AS sa ON (sa.id = m.sender
diff --combined modules/search.php
@@@ -49,33 -49,30 +49,33 @@@ class SearchModule extends PLModul
              $school = Env::i('school');
          }
  
 -        if (!is_null($school)) {
 -            $sql = 'SELECT type FROM applis_def WHERE id=' . $school;
 +        if ((!is_null($school)) && ($school != '')) {
 +            $sql = 'SELECT  degreeid
 +                      FROM  profile_education_degree
 +                     WHERE  eduid=' . $school;
          } else {
 -            $sql = 'DESCRIBE applis_def type';
 +            $sql = 'SELECT  id
 +                      FROM  profile_education_degree_enum
 +                  ORDER BY  id';
          }
  
          $res = XDB::query($sql);
 -        $row = $res->fetchOneRow();
 -        if (!is_null($school)) {
 -            $types = $row[0];
 -        } else {
 -            $types = explode('(',$row[1]);
 -            $types = str_replace("'","",substr($types[1],0,-1));
 -        }
 -        Platal::page()->assign('choix_diplomas', explode(',',$types));
 +        Platal::page()->assign('choix_diplomas', $res->fetchColumn());
 +
 +        $sql = 'SELECT  degree
 +                  FROM  profile_education_degree_enum
 +              ORDER BY  id';
 +        $res = XDB::query($sql);
 +        Platal::page()->assign('name_diplomas', $res->fetchColumn());
      }
  
      function handler_quick(&$page, $action = null, $subaction = null)
      {
          global $globals;
  
-         $res = XDB::query("SELECT  MIN(`diminutif`), MAX(`diminutif`)
-                              FROM  `groupex`.`asso`
-                             WHERE  `cat` = 'Promotions'");
+         $res = XDB::query("SELECT  MIN(diminutif), MAX(diminutif)
+                              FROM  #groupex#.asso
+                             WHERE  cat = 'Promotions'");
          list($min, $max) = $res->fetchOneRow();
          $page->assign('promo_min', $min);
          $page->assign('promo_max', $max);
              $this->form_prepare();
          } else {
              $textFields = array(
 -                'country' => array('field' => 'a2', 'table' => 'geoloc_pays', 'text' => 'pays', 'exact' => false),
 -                'fonction' => array('field' => 'id', 'table' => 'fonctions_def', 'text' => 'fonction_fr', 'exact' => true),
 -                'secteur' => array('field' => 'id', 'table' => 'emploi_secteur', 'text' => 'label', 'exact' => false),
 -                'nationalite' => array('field' => 'a2', 'table' => 'geoloc_pays', 'text' => 'nat', 'exact' => 'false'),
 -                'binet' => array('field' => 'id', 'table' => 'binets_def', 'text' => 'text', 'exact' => false),
 -                'groupex' => array('field' => 'id', 'table' => '#groupex#.asso',
 -                                   'text' => "(cat = 'GroupesX' OR cat = 'Institutions') AND pub = 'public' AND nom",
 -                                   'exact' => false),
 -                'section' => array('field' => 'id', 'table' => 'sections', 'text' => 'text', 'exact' => false),
 -                'school' => array('field' => 'id', 'table' => 'applis_def', 'text' => 'text', 'exact' => false),
 -                'city' => array('table' => 'geoloc_city', 'text' => 'name', 'exact' => false)
 +                'country'         => array('field' => 'iso_3166_1_a2', 'table' => 'geoloc_countries', 'text' => 'countryFR',
 +                                           'exact' => false),
 +                'fonction'        => array('field' => 'id', 'table' => 'fonctions_def', 'text' => 'fonction_fr', 'exact' => true),
 +                'secteur'         => array('field' => 'id', 'table' => 'profile_job_sector_enum', 'text' => 'name', 'exact' => false),
 +                'nationalite'     => array('field' => 'iso_3166_1_a2', 'table' => 'geoloc_countries', 
 +                                           'text' => 'nationalityFR', 'exact' => 'false'),
 +                'binet'           => array('field' => 'id', 'table' => 'binets_def', 'text' => 'text', 'exact' => false),
 +                'networking_type' => array('field' => 'network_type', 'table' => 'profile_networking_enum',
 +                                           'text' => 'name', 'exact' => false),
-                 'groupex'         => array('field' => 'id', 'table' => 'groupex.asso',
++                'groupex'         => array('field' => 'id', 'table' => '#groupex#.asso',
 +                                           'text' => "(cat = 'GroupesX' OR cat = 'Institutions') AND pub = 'public' AND nom",
 +                                           'exact' => false),
 +                'section'         => array('field' => 'id', 'table' => 'sections', 'text' => 'text', 'exact' => false),
 +                'school'          => array('field' => 'id', 'table' => 'profile_education_enum', 'text' => 'name', 'exact' => false),
 +                'city'            => array('table' => 'geoloc_localities', 'text' => 'name', 'exact' => false)
              );
              if (!Env::has('page')) {
                  S::logger()->log('search', 'adv=' . var_export($_GET, true));
          //   result1|nb1
          //   result2|nb2
          //   ...
-         header('Content-Type: text/plain; charset="UTF-8"');
+         pl_content_headers("text/plain");
          $q = preg_replace(array('/\*+$/', // always look for $q*
                                  '/([\^\$\[\]])/', // escape special regexp char
                                  '/\*/'), // replace joker by regexp joker
          $beginwith = true;
          $field2 = false;
          $qsearch = str_replace(array('%', '_'), '', $q);
 +        $distinct = true;
  
          switch ($type) {
            case 'binetTxt':
              $db = '`binets_def` INNER JOIN
                     `binets_ins` ON(`binets_def`.`id` = `binets_ins`.`binet_id`)';
 -            $field='`binets_def`.`text`';
 +            $field = '`binets_def`.`text`';
              if (strlen($q) > 2)
                  $beginwith = false;
              $realid = '`binets_def`.`id`';
              break;
 +          case 'networking_typeTxt':
 +            $db = '`profile_networking_enum` INNER JOIN
 +                   `profile_networking` ON(`profile_networking`.`network_type` = `profile_networking_enum`.`network_type`)';
 +            $field = '`profile_networking_enum`.`name`';
 +            $unique = 'uid';
 +            $realid = '`profile_networking_enum`.`network_type`';
 +            break;
            case 'city':
 -            $db = '`geoloc_city` INNER JOIN
 -                   `adresses` ON(`geoloc_city`.`id` = `adresses`.`cityid`)';
 -            $unique='`uid`';
 -            $field='`geoloc_city`.`name`';
 +            $db     = 'geoloc_localities INNER JOIN
 +                       profile_addresses ON (geoloc_localities.id = profile_addresses.localityId)';
 +            $unique = 'uid';
 +            $field  ='geoloc_localities.name';
              break;
            case 'countryTxt':
 -            $db = '`geoloc_pays` INNER JOIN
 -                   `adresses` ON(`geoloc_pays`.`a2` = `adresses`.`country`)';
 -            $unique='`uid`';
 -            $field = '`geoloc_pays`.`pays`';
 -            $field2 = '`geoloc_pays`.`country`';
 -            $realid='`geoloc_pays`.`a2`';
 +            $db     = 'geoloc_countries INNER JOIN
 +                       profile_addresses ON (geoloc_countries.iso_3166_1_a2 = profile_addresses.countryId)';
 +            $unique = 'pid';
 +            $field  = 'geoloc_countries.countryFR';
 +            $realid = 'geoloc_countries.iso_3166_1_a2';
              break;
            case 'entreprise':
 -            $db = '`entreprises`';
 -            $field = '`entreprise`';
 -            $unique='`uid`';
 -            break;
 -          case 'firstname':
 -            $field = '`prenom`';
 -            $beginwith = false;
 +            $db     = 'profile_job_enum INNER JOIN
 +                       profile_job ON (profile_job.jobid = profile_job_enum.id)';
 +            $field  = 'profile_job_enum.name';
 +            $unique = 'profile_job.uid';
              break;
            case 'fonctionTxt':
 -            $db = '`fonctions_def` INNER JOIN
 -                   `entreprises` ON(`entreprises`.`fonction` = `fonctions_def`.`id`)';
 -            $field = '`fonction_fr`';
 -            $unique = '`uid`';
 -            $realid = '`fonctions_def`.`id`';
 +            $db        = 'fonctions_def INNER JOIN
 +                          profile_job ON (profile_job.fonctionid = fonctions_def.id)';
 +            $field     = 'fonction_fr';
 +            $unique    = 'uid';
 +            $realid    = 'fonctions_def.id';
              $beginwith = false;
              break;
            case 'groupexTxt':
-             $db = "groupex.asso AS a INNER JOIN
-                    groupex.membres AS m ON(a.id = m.asso_id
+             $db = "#groupex#.asso AS a INNER JOIN
+                    #groupex#.membres AS m ON(a.id = m.asso_id
                                             AND (a.cat = 'GroupesX' OR a.cat = 'Institutions')
                                             AND a.pub = 'public')";
              $field='a.nom';
              $realid = 'a.id';
              $unique = 'm.uid';
              break;
 -          case 'name':
 -            $field = '`nom`';
 -            $field2 = '`nom_usage`';
 -            $beginwith = false;
 -            break;
            case 'nationaliteTxt':
 -            $db = '`geoloc_pays` INNER JOIN
 -                   `auth_user_md5` ON(`geoloc_pays`.`a2` = `auth_user_md5`.`nationalite`)';
 -            $field = 'IF(`geoloc_pays`.`nat`=\'\',
 -                                       `geoloc_pays`.`pays`,
 -                                       `geoloc_pays`.`nat`)';
 -            $realid = '`geoloc_pays`.`a2`';
 +            $db     = 'geoloc_countries INNER JOIN
 +                       auth_user_md5 ON (geoloc_countries.a2 = auth_user_md5.nationalite
 +                                         OR geoloc_countries.a2 = auth_user_md5.nationalite2
 +                                         OR geoloc_countries.a2 = auth_user_md5.nationalite3)';
 +            $field  = 'geoloc_countries.nationalityFR';
 +            $realid = 'geoloc_countries.iso_3166_1_a2';
              break;
 -          case 'nickname':
 -            $field = '`profile_nick`';
 -            $db = '`auth_user_quick`';
 -            $beginwith = false;
 -            break;
 -          case 'poste':
 -            $db = '`entreprises`';
 -            $field = '`poste`';
 -            $unique='`uid`';
 +          case 'description':
 +            $db     = 'profile_job';
 +            $field  = 'description';
 +            $unique = 'uid';
              break;
            case 'schoolTxt':
 -            $db = '`applis_def` INNER JOIN
 -                   `applis_ins` ON(`applis_def`.`id` = `applis_ins`.`aid`)';
 -            $field='`applis_def`.`text`';
 -            $unique = '`uid`';
 -            $realid = '`applis_def`.`id`';
 +            $db = 'profile_education_enum INNER JOIN
 +                   profile_education ON (profile_education_enum.id = profile_education.eduid)';
 +            $field = 'profile_education_enum.name';
 +            $unique = 'uid';
 +            $realid = 'profile_education_enum.id';
              if (strlen($q) > 2)
                  $beginwith = false;
              break;
            case 'secteurTxt':
 -            $db = '`emploi_secteur` INNER JOIN
 -                   `entreprises` ON(`entreprises`.`secteur` = `emploi_secteur`.`id`)';
 -            $field = '`emploi_secteur`.`label`';
 -            $realid = '`emploi_secteur`.`id`';
 -            $unique = '`uid`';
 +            $db        = 'profile_job_sector_enum INNER JOIN
 +                          profile_job ON (profile_job.sectorid = profile_job_sector_enum.id)';
 +            $field     = 'profile_job_sector_enum.name';
 +            $realid    = 'profile_job_sector_enum.id';
 +            $unique    = 'uid';
              $beginwith = false;
              break;
 +          case 'subSubSector':
 +            $db        = 'profile_job_subsubsector_enum';
 +            $field     = 'name';
 +            $beginwith = false;
 +            $unique    = 'name';
 +            $distinct  = false;
 +            break;
            case 'sectionTxt':
              $db = '`sections` INNER JOIN
                     `auth_user_md5` ON(`auth_user_md5`.`section` = `sections`.`id`)';
              $field2_t = make_field_test($field2, $beginwith);
              $field_select = 'IF(' . $field_t . ', ' . $field . ', ' . $field2. ')';
          }
 -        $list = XDB::iterator('SELECT  ' . $field_select . ' AS field,
 -                                       COUNT(DISTINCT ' . $unique . ') AS nb
 -                                       . ($realid ? (', ' . $realid . ' AS id') : '') . '
 +        $list = XDB::iterator('SELECT  ' . $field_select . ' AS field'
 +                                       . ($distinct ? (', COUNT(DISTINCT ' . $unique . ') AS nb') : '')
 +                                       . ($realid ? (', ' . $realid . ' AS id') : '') . '
                                   FROM  ' . $db . '
                                  WHERE  ' . $field_t .
                                          ($field2 ? (' OR ' . $field2_t) : '') . '
                               GROUP BY  ' . $field_select . '
 -                             ORDER BY  nb DESC
 +                             ORDER BY  ' . ($distinct ? 'nb DESC' : $field_select) . '
                                  LIMIT  11',
                                 $qsearch, $qsearch, $qsearch, $qsearch, $qsearch, $qsearch, $qsearch, $qsearch,
                                 $qsearch, $qsearch, $qsearch, $qsearch, $qsearch, $qsearch, $qsearch, $qsearch);
 +
          $nbResults = 0;
          $res = "";
          while ($result = $list->next()) {
                  $res .= $q."|-1\n";
              } else {
                  $res .= $result['field'].'|';
 -                $res .= $result['nb'];
 +                if (isset($result['nb'])) {
 +                    $res .= $result['nb'];
 +                }
                  if (isset($result['id'])) {
                      $res  .= '|'.$result['id'];
                  }
            case 'binet':
              $db = '`binets_def`';
              break;
 +          case 'networking_type':
 +            $db = '`profile_networking_enum`';
 +            $field = '`name`';
 +            $id = '`network_type`';
 +            break;
            case 'country':
 -            $db = '`geoloc_pays`';
 -            $field = '`pays`';
 -            $id = '`a2`';
 +            $db    = 'geoloc_countries';
 +            $field = 'countryFR';
 +            $id    = 'iso_3166_1_a2';
              $page->assign('onchange', 'changeCountry(this.value)');
              break;
            case 'fonction':
              $field = '`fonction_fr`';
              break;
            case 'diploma':
-             header('Content-Type: text/xml; charset="UTF-8"');
+             pl_content_headers("text/xml");
              $this->get_diplomas();
              $page->changeTpl('search/adv.grade.form.tpl', NO_SKIN);
              return;
            case 'groupex':
-             $db = 'groupex.asso';
+             $db = '#groupex#.asso';
              $where = " WHERE (cat = 'GroupesX' OR cat = 'Institutions') AND pub = 'public'";
              $field = 'nom';
              break;
            case 'nationalite':
 -            $db = '`geoloc_pays` INNER JOIN
 -                   `auth_user_md5` ON (`geoloc_pays`.`a2` = `auth_user_md5`.`nationalite`)';
 -            $field = 'IF(`nat`=\'\', `pays`, `nat`)';
 -            $id = '`a2`';
 +            $db    = 'geoloc_countries INNER JOIN
 +                      auth_user_md5 ON (geoloc_countries.iso_3166_1_a2 = auth_user_md5.nationalite
 +                                        OR geoloc_countries.iso_3166_1_a2 = auth_user_md5.nationalite2
 +                                        OR geoloc_countries.iso_3166_1_a2 = auth_user_md5.nationalite3)';
 +            $field = 'nationalityFR';
 +            $id    = 'iso_3166_1_a2';
              break;
            case 'region':
 -            $db = '`geoloc_region`';
 -            $field = '`name`';
 -            $id = '`region`';
 +            $db    = 'geoloc_administrativeareas';
 +            $field = 'name';
 +            $id    = 'id';
              if (isset($_REQUEST['country'])) {
 -                $where .= ' WHERE `a2` = "'.$_REQUEST['country'].'"';
 +                $where .= ' WHERE country = "' . $_REQUEST['country'] . '"';
              }
              break;
            case 'school':
 -            $db = '`applis_def`';
 +            $db = 'profile_education_enum';
 +            $field = 'name';
 +            $id = 'id';
              $page->assign('onchange', 'changeSchool(this.value)');
              break;
            case 'section':
              $db = '`sections`';
              break;
            case 'secteur':
 -            $db = '`emploi_secteur`';
 -            $field = '`label`';
 +            $db    = 'profile_job_sector_enum INNER JOIN
 +                      profile_job ON (profile_job.sectorid = profile_job_sector_enum.id)';
 +            $field = 'profile_job_sector_enum.name';
 +            $id    = 'profile_job_sector_enum.id';
              break;
            default: exit();
          }
          if (isset($idVal)) {
-             header('Content-Type: text/plain; charset="UTF-8"');
+             pl_content_headers("text/plain");
              $result = XDB::query('SELECT '.$field.' AS field FROM '.$db.' WHERE '.$id.' = {?} LIMIT 1',$idVal);
              echo $result->fetchOneCell();
              exit();
          }
-         header('Content-Type: text/xml; charset="UTF-8"');
+         pl_content_headers("text/xml");
          $page->changeTpl('include/field.select.tpl', NO_SKIN);
          $page->assign('name', $type);
          $page->assign('list', XDB::iterator('SELECT  '.$field.' AS field,
      u.perms IN (\'admin\',\'user\', \'disabled\') AS inscrit,
      u.perms != \'pending\' AS wasinscrit,
      FIND_IN_SET(\'femme\', u.flags) AS sexe,
 -    a.alias AS forlife,
 -    ad0.text AS app0text, ad0.url AS app0url, ai0.type AS app0type,
 -    ad1.text AS app1text, ad1.url AS app1url, ai1.type AS app1type,
 -    es.label AS secteur, ef.fonction_fr AS fonction,
 -    IF(n.nat=\'\',n.pays,n.nat) AS nat, n.a2 AS iso3166,
 +    ede0.name AS eduname0, ede0.url AS eduurl0, edd0.degree AS edudegree0,
 +    edu0.grad_year AS edugrad_year0, f0.field AS edufield0, edu0.program AS eduprogram0,
 +    ede1.name AS eduname1, ede1.url AS eduurl1, edd1.degree AS edudegree1,
 +    edu1.grad_year AS edugrad_year1, f1.field AS edufield1, edu1.program AS eduprogram1,
 +    ede2.name AS eduname2, ede2.url AS eduurl2, edd2.degree AS edudegree2,
 +    edu2.grad_year AS edugrad_year2, f2.field AS edufield2, edu2.program AS eduprogram2,
 +    ede3.name AS eduname3, ede3.url AS eduurl3, edd3.degree AS edudegree3,
 +    edu3.grad_year AS edugrad_year3, f3.field AS edufield3, edu3.program AS eduprogram3,
 +    es.name AS secteur, ef.fonction_fr AS fonction,
 +    IF(n1.nat=\'\',n1.pays,n1.nat) AS nat1, n1.a2 AS iso3166_1,
 +    IF(n2.nat=\'\',n2.pays,n2.nat) AS nat2, n2.a2 AS iso3166_2,
 +    IF(n3.nat=\'\',n3.pays,n3.nat) AS nat3, n3.a2 AS iso3166_3,
      (COUNT(em.email) > 0 OR FIND_IN_SET("googleapps", u.mail_storage) > 0) AS actif,';
  // hide private information if not logged
  if (S::logged())
      $globals->search->result_fields .='
 -        q.profile_web AS web,
 -        q.profile_mobile AS mobile,
          q.profile_freetext AS freetext,
          adr.city, gp.pays AS countrytxt, gr.name AS region,
 -        e.entreprise,';
 +        ee.name,
 +        nw.address AS networking_address,
 +        nwe.name AS networking_name,';
  else
      $globals->search->result_fields .="
 -    IF(q.profile_web_pub='public', q.profile_web, '') AS web,
 -        IF(q.profile_mobile_pub='public', q.profile_mobile, '') AS mobile,
          IF(q.profile_freetext_pub='public', q.profile_freetext, '') AS freetext,
 -        IF(adr.pub='public', adr.city, '') AS city,
 -        IF(adr.pub='public', gp.pays, '') AS countrytxt,
 -        IF(adr.pub='public', gr.name, '') AS region,
 -        IF(e.pub='public', e.entreprise, '') AS entreprise,";
 -@$globals->search->result_where_statement = '
 -    LEFT JOIN  applis_ins     AS ai0 ON (u.user_id = ai0.uid AND ai0.ordre = 0)
 -    LEFT JOIN  applis_def     AS ad0 ON (ad0.id = ai0.aid)
 -    LEFT JOIN  applis_ins     AS ai1 ON (u.user_id = ai1.uid AND ai1.ordre = 1)
 -    LEFT JOIN  applis_def     AS ad1 ON (ad1.id = ai1.aid)
 -    LEFT JOIN  entreprises    AS e   ON (e.entrid = 0 AND e.uid = u.user_id)
 -    LEFT JOIN  emploi_secteur AS es  ON (e.secteur = es.id)
 -    LEFT JOIN  fonctions_def  AS ef  ON (e.fonction = ef.id)
 -    LEFT JOIN  geoloc_pays    AS n   ON (u.nationalite = n.a2)
 -    LEFT JOIN  adresses       AS adr ON (u.user_id = adr.uid AND FIND_IN_SET(\'active\',adr.statut))
 -    LEFT JOIN  geoloc_pays    AS gp  ON (adr.country = gp.a2)
 -    LEFT JOIN  geoloc_region  AS gr  ON (adr.country = gr.a2 AND adr.region = gr.region)
 -    LEFT JOIN  emails         AS em  ON (em.uid = u.user_id AND em.flags = \'active\')';
 +        IF(adr.pub='public', adr.city, '')   AS city,
 +        IF(adr.pub='public', gp.pays, '')    AS countrytxt,
 +        IF(adr.pub='public', gr.name, '')    AS region,
 +        IF(e.pub='public', je.name, '')      AS entreprise,
 +        IF(nw.pub='public', nw.address, '')  AS networking_address,
 +        IF(nw.pub='public', nwe.name, '')    AS networking_name,";
 +@$globals->search->result_where_statement = "
 +    LEFT JOIN  profile_education             AS edu0 ON (u.user_id = edu0.uid AND edu0.id = 0)
 +    LEFT JOIN  profile_education_enum        AS ede0 ON (ede0.id = edu0.eduid)
 +    LEFT JOIN  profile_education_degree_enum AS edd0 ON (edd0.id = edu0.degreeid)
 +    LEFT JOIN  profile_education_field_enum  AS f0   ON (f0.id = edu0.fieldid)
 +    LEFT JOIN  profile_education             AS edu1 ON (u.user_id = edu1.uid AND edu1.id = 1)
 +    LEFT JOIN  profile_education_enum        AS ede1 ON (ede1.id = edu1.eduid)
 +    LEFT JOIN  profile_education_degree_enum AS edd1 ON (edd1.id = edu1.degreeid)
 +    LEFT JOIN  profile_education_field_enum  AS f1   ON (f1.id = edu1.fieldid)
 +    LEFT JOIN  profile_education             AS edu2 ON (u.user_id = edu2.uid AND edu2.id = 2)
 +    LEFT JOIN  profile_education_enum        AS ede2 ON (ede2.id = edu2.eduid)
 +    LEFT JOIN  profile_education_degree_enum AS edd2 ON (edd2.id = edu2.degreeid)
 +    LEFT JOIN  profile_education_field_enum  AS f2   ON (f2.id = edu2.fieldid)
 +    LEFT JOIN  profile_education             AS edu3 ON (u.user_id = edu3.uid AND edu3.id = 3)
 +    LEFT JOIN  profile_education_enum        AS ede3 ON (ede3.id = edu3.eduid)
 +    LEFT JOIN  profile_education_degree_enum AS edd3 ON (edd3.id = edu3.degreeid)
 +    LEFT JOIN  profile_education_field_enum  AS f3   ON (f3.id = edu3.fieldid)
 +    LEFT JOIN  profile_job                   AS e    ON (e.uid = u.user_id)
 +    LEFT JOIN  profile_job_enum              AS ee   ON (e.jobid = ee.id)
 +    LEFT JOIN  profile_job_sector_enum       AS es   ON (es.id = e.sectorid)
 +    LEFT JOIN  fonctions_def                 AS ef   ON (e.fonction = ef.id)
 +    LEFT JOIN  geoloc_countries              AS n1   ON (u.nationalite = n1.iso_3166_1_a2)
 +    LEFT JOIN  geoloc_countries              AS n2   ON (u.nationalite2 = n2.iso_3166_1_a2)
 +    LEFT JOIN  geoloc_countries              AS n3   ON (u.nationalite3 = n3.iso_3166_1_a2)
 +    LEFT JOIN  profile_addresses             AS adr  ON (u.user_id = adr.pid
 +                                                         AND FIND_IN_SET('current', adr.flags))
 +    LEFT JOIN  geoloc_countries              AS gp   ON (adr.countryId = gp.iso_3166_1_a2)
 +    LEFT JOIN  geoloc_administrativeareas    AS gr   ON (adr.countryId = gr.country
 +                                                         AND adr.administrativeAreaId = gr.id)
 +    LEFT JOIN  emails                        AS em   ON (em.uid = u.user_id AND em.flags = 'active')
 +    LEFT JOIN  profile_networking            AS nw   ON (nw.uid = u.user_id)
 +    LEFT JOIN  profile_networking_enum       AS nwe  ON (nwe.network_type = nw.network_type)";
  
  // }}}
  // {{{ class ThrowError
@@@ -235,8 -209,6 +235,8 @@@ class QuickSearch extends SFiel
      /** stores admin searches */
      var $email;
      var $ip;
 +    /** stores phone number */
 +    var $phone;
  
      // }}}
      // {{{ constructor
  
      function isempty()
      {
 -        return empty($this->strings) && empty($this->ranges) && empty($this->email) && empty($this->ip);
 +        return empty($this->strings) && empty($this->ranges) && empty($this->email) && empty($this->ip) && empty($this->phone);
      }
  
      // }}}
          foreach ($ranges as $r) {
              if (preg_match('!^([<>]\d{4}|\d{4}(-\d{4})?)$!', $r)) $this->ranges[] = $r;
          }
 +
 +        $t = preg_replace('!(\d{4}-\d{4}|>\d{4}|<\d{4})!', '', $s);
 +        $t = preg_replace('![<>\- ]!', '', $t);
 +        if (strlen($t) > 4) {
 +            $this->phone = $t;
 +        }
      }
  
      // }}}
                  $where[] = "false";
              }
          }
 +        if (!empty($this->phone)){
 +            require_once("profil.func.inc.php");
 +            $phone = format_phone_number($this->phone) . "%";
 +            $where[] = 't.search_tel LIKE ' . XDB::escape($phone);
 +        }
  
          return join(" AND ", $where);
      }
              $join .= "LEFT JOIN emails AS ems ON (ems.uid = u.user_id)";
          }
          if (!empty($this->ip)) {
-             $join .= "INNER JOIN logger.sessions AS ls ON (ls.uid = u.user_id)\n";
+             $join .= "INNER JOIN #logger#.sessions AS ls ON (ls.uid = u.user_id)\n";
          }
 +        if (!empty($this->phone)) {
 +            if (!S::logged()) {
 +                $join .= "INNER JOIN profile_phones AS t ON (t.uid = u.user_id AND t.pub = 'public')";
 +            } else {
 +                $join .= "INNER JOIN profile_phones AS t ON (t.uid = u.user_id)";
 +            }
 +        }
          return $join;
      }
      // }}}
@@@ -545,39 -499,6 +545,39 @@@ class RefSField extends SFiel
  // }}}
  
  // {{{ class RefSFieldMultipleTable
 +class PhoneSField extends RefSField
 +{
 +    function PhoneSField($_fieldFormName, $_fieldDbName='', $_refTable, $_refAlias, $_refCondition)
 +    {
 +        $this->RefSField($_fieldFormName, $_fieldDbName, $_refTable, $_refAlias, $_refCondition, true);
 +    }
 +
 +    function get_request()
 +    {
 +        require_once("profil.func.inc.php");
 +        $this->value = trim(Env::v($this->fieldFormName));
 +        $this->value = format_phone_number($this->value);
 +    }
 +
 +    function compare()
 +    {
 +        return " LIKE '" . addslashes($this->value) . "%'";
 +    }
 +}
 +
 +class IndexSField extends RefSField
 +{
 +    function IndexSField($_fieldFormName, $_fieldDbName='', $_refTable, $_refAlias, $_refCondition)
 +    {
 +        $this->RefSField($_fieldFormName, $_fieldDbName, $_refTable, $_refAlias, $_refCondition, true);
 +    }
 +
 +    function get_request()
 +    {
 +        $this->value = trim(Env::v($this->fieldFormName));
 +    }
 +}
 +
  class MapSField extends RefSField
  {
      var $mapId;
  require_once dirname(__FILE__).'/classes.inc.php';
  
  // {{{ function advancedSearchFromInput
 -function getadr_join($table) {
 -    return 'u.user_id='.$table.'.uid'.(Env::v('only_current',false)?' AND FIND_IN_SET(\'active\','.$table.'.statut)':'');
 +function getAddressJoin($table) {
 +    return 'u.user_id = ' . $table . '.pid' . (Env::v('only_current', false) ? ' AND FIND_IN_SET(\'current\', ' . $table . '.flags)' : '');
  }
  function advancedSearchFromInput()
  {
      if ($with_soundex = Env::has('with_soundex')) {
 -        $nameField      = new RefWithSoundexSField('name',array('rn.nom1_soundex','rn.nom2_soundex','rn.nom3_soundex'),'recherche_soundex','rn','u.matricule = rn.matricule');
 -        $firstnameField = new RefWithSoundexSField('firstname',array('rp.prenom1_soundex','rp.prenom2_soundex'),'recherche_soundex','rp','u.matricule = rp.matricule');
 +        $nameField      = new RefWithSoundexSField('name', array('n.soundex'), 'search_name',
 +                                                   'n', 'u.user_id = n.uid');
      } else {
 -        $nameField      = new NameSField('name',array('u.nom','u.nom_usage'),'');
 -        $firstnameField = new StringSField('firstname',array('u.prenom'),'');
 +        $nameField      = new NameSField('name', array('n.token'), 'search_name', 'n', 'u.user_id = n.uid');
      }
 -    $nicknameField   = new StringSField('nickname',array('q.profile_nick'),'');
  
 -    $promo1Field     = new PromoSField('promo1','egal1',array('u.promo'),'');
 -    $promo2Field     = new PromoSField('promo2','egal2',array('u.promo'),'');
 -    $womanField      = new RefSField('woman',array('FIND_IN_SET(\'femme\',u.flags)+1'),'','','');
 -    $subscriberField = new RefSField('subscriber',array('!(u.perms IN (\'admin\',\'user\'))+1'),'','','');
 -    $aliveField      = new RefSField('alive',array('(u.deces!=0)+1'),'','','');
 +    $promo1Field        = new PromoSField('promo1', 'egal1', array('u.promo'), '');
 +    $promo2Field        = new PromoSField('promo2', 'egal2', array('u.promo'), '');
 +    $womanField         = new RefSField('woman', array('FIND_IN_SET(\'femme\', u.flags) + 1'), '', '', '');
 +    $subscriberField    = new RefSField('subscriber', array('!(u.perms IN (\'admin\', \'user\')) + 1'), '', '', '');
 +    $aliveField         = new RefSField('alive', array('(u.deces != 0) + 1'), '', '', '');
      if (Env::v('only_referent') == 'on') {
 -        $referentField = new RefSField('only_referent', array('"on"'), 'mentor', 'mt', 'mt.expertise != "" AND mt.uid=u.user_id');
 +        $referentField  = new RefSField('only_referent', array('"on"'), 'mentor', 'mt', 'mt.expertise != "" AND mt.uid = u.user_id');
      } else {
 -        $referentField = null;
 +        $referentField  = null;
      }
  
 -    if (!Env::i('cityid')) {
 -        $townField  = new RefSField('city',array('ac.city', 'ac.postcode'),'adresses','ac',getadr_join('ac'),false);
 -    } else {
 -        $townField  = new RefSField('cityid',array('av.cityid', 'av.postcode'),'adresses','av',getadr_join('av'));
 -    }
 -    $countryField   = new RefSField('country',array('ap.country'),'adresses','ap',getadr_join('ap'));
 -    $regionField    = new RefSField('region',array('ar.region'),'adresses','ar',getadr_join('ar'));
 -    $mapField       = new MapSField('mapid', array('sgcim.map_id'), array('adresses','geoloc_city_in_maps'), array('amp','sgcim'), array(getadr_join('amp'), 'amp.cityid = sgcim.city_id'));
 +    $townField          = new RefSField('city', array('av.localityId', 'av.postalCode'), 'profile_addresses',
 +                                        'av', getAddressJoin('av'));
 +    $countryField       = new RefSField('country', array('ap.countryId'), 'profile_addresses', 'ap', getAddressJoin('ap'));
 +    $regionField        = new RefSField('region',array('ar.administrativeAreaId'), 'profile_addresses', 'ar', getAddressJoin('ar'));
  
 -    $entrepriseField = new RefSField('entreprise',array('ee.entreprise'),'entreprises','ee','u.user_id=ee.uid',false);
 -    $posteField      = new RefSField('poste',array('ep.poste'),'entreprises','ep','u.user_id=ep.uid', false);
 -    $fonctionField = new RefSField('fonction',array('en.fonction'),'entreprises','en','u.user_id=en.uid');
 -    $secteurField    = new RefSField('secteur',array('fm.secteur'),'entreprises','fm','u.user_id=fm.uid');
 -    $cvField         = new RefSField('cv',array('u.cv'),'','','',false);
 +    $entrepriseField    = new RefSField('entreprise', array('je.name'), '', '','');
 +    $posteField         = new RefSField('poste', array('ep.description'), 'profile_job', 'ep', 'u.user_id = ep.uid', false);
 +    $fonctionField      = new RefSField('fonction', array('en.fonction_fr'), 'fonctions_def', 'en',
 +                                        'u.user_id = profile_job.uid AND fonctions_def.id = profile_job.functionid');
 +    $secteurField       = new RefSField('secteur', array('fm.sectorid'), 'profile_job', 'fm', 'u.user_id = fm.uid');
 +    $cvField            = new RefSField('cv', array('u.cv'), '', '', '', false);
  
 -    $natField        = new RefSField('nationalite',array('u.nationalite'),'','','');
 -    $binetField      = new RefSField('binet',array('b.binet_id'),'binets_ins','b','u.user_id=b.user_id');
 -    $groupexField    = new RefSField('groupex',array('g.id'),array('#groupex#.asso', '#groupex#.membres'),array('g', 'gm'),
 -                                     array("(g.cat = 'GroupesX' OR g.cat = 'Institutions') AND g.pub = 'public'",
 -                                           'gm.asso_id = g.id AND u.user_id=gm.uid'));
 -    $sectionField    = new RefSField('section',array('u.section'),'','','');
 -    $schoolField     = new RefSField('school',array('as.aid'),'applis_ins','`as`','u.user_id=as.uid');
 -    $diplomaField    = new RefSField('diploma',array('ad.type'),'applis_ins','ad','u.user_id=ad.uid');
 +    $natField           = new RefSField('nationalite', array('u.nationalite', 'u.nationalite2', 'u.nationalite3'), '', '', '');
 +    $binetField         = new RefSField('binet', array('b.binet_id'), 'binets_ins', 'b', 'u.user_id=b.user_id');
-     $groupexField       = new RefSField('groupex', array('g.id'), array('groupex.asso', 'groupex.membres'), array('g', 'gm'),
++    $groupexField       = new RefSField('groupex', array('g.id'), array('#groupex#.asso', '#groupex#.membres'), array('g', 'gm'),
 +                                        array("(g.cat = 'GroupesX' OR g.cat = 'Institutions') AND g.pub = 'public'",
 +                                              'gm.asso_id = g.id AND u.user_id = gm.uid'));
 +    $sectionField       = new RefSField('section', array('u.section'), '', '', '');
 +    $schoolField        = new RefSField('school', array('edu.eduid'), 'profile_education', 'edu', 'u.user_id = edu.uid');
 +    $diplomaField       = new RefSField('diploma', array('edd.degreeid'), 'profile_education', 'edd', 'u.user_id = edd.uid');
  
 -    $freeField       = new RefSField('free',array('q.profile_freetext'),'','','',false);
 +    $freeField          = new RefSField('free', array('q.profile_freetext'), '', '', '', false);
  
 +    $nwAddressField     = new RefSField('networking_address', array('nw.address'), 'profile_networking', 'nw', 'nw.uid=u.user_id', false);
 +    if (Env::v('networking_address') == '') {
 +        $nwTypeField    = new IndexSField('networking_type', array('nwe.network_type'), array('profile_networking', 'profile_networking_enum'),
 +                                          array('nw', 'nwe'), array('nw.uid = u.user_id', 'nwe.network_type = nw.network_type'));
 +    } else {
 +        $nwTypeField    = new IndexSField('networking_type',
 +                                          array('nwe.network_type'), 'profile_networking_enum', 'nwe', 'nwe.network_type = nw.network_type');
 +    }
 +    $nwPhoneField       = new PhoneSField('phone_number', array('t.search_tel'), 'profile_phones', 't', 't.uid = u.user_id');
      return array(
 -                $nameField, $firstnameField, $nicknameField, $promo1Field,
 -                $promo2Field, $womanField, $subscriberField, $aliveField, $referentField,
 -                $townField, $countryField, $regionField, $mapField, $entrepriseField,
 +                $nameField, $promo1Field,
 +                $promo2Field, $womanField, $subscriberField, $aliveField,
 +                $townField, $countryField, $regionField, $entrepriseField,
                  $posteField, $secteurField, $cvField, $natField, $binetField,
                  $groupexField, $sectionField, $schoolField, $diplomaField,
 -                $freeField, $fonctionField);
 +                $freeField, $fonctionField, $nwAddressField, $nwTypeField,
 +                $nwPhoneField, $referentField);
  }
  
  // }}}
          <td class="titre">Type de sondage&nbsp;:</td>
          <td>{$survey_modes[$survey.mode]}</td>
        </tr>
 -      {if $survey.mode != Survey::MODE_ALL} 
 +      {if $survey.mode != Survey::MODE_ALL}
        <tr>
 -        <td class="titre">Promotions&nbsp;:</td> 
 +        <td class="titre">Promotions&nbsp;:</td>
          <td>
-           {if $survey.promos eq "#"}
-           erreur
-           {elseif $survey.promos eq ""}
-           aucune restriction
-           {else}
-           {$survey.promos}
+           {if $survey.promos eq "#"} 
+           <span class="erreur">erreur</span>
+           {elseif $survey.promos eq ""} 
+           aucune restriction 
+           {else} 
+           {$survey.promos} 
            {/if}
          </td>
        </tr>
@@@ -58,8 -58,8 +58,8 @@@
        {/if}
      </table>
      {if $survey_resultmode}
-     <p class="smaller">{$survey.votes} personnes ont r&#233;pondu &#224; ce sondage.<br />
-       R&#233;cup&#233;rer <a href="survey/result/{$survey.id}/csv">l'ensemble des r&#233;sultats</a> au format csv
+     <p class="smaller">{$survey.votes} personnes ont répondu à ce sondage.<br />
+       Récupérer <a href="survey/result/{$survey.id}/csv">l'ensemble des résultats</a> au format csv
      </p>
      {/if}
      </td>
@@@ -67,9 -67,9 +67,9 @@@
        {assign var="survey_editallmode" value=true}
      {/if}
      {if $survey_editmode}
-     <td class="smaller" style="width: 30%">
+     <td style="width: 30%">
        <a href='survey/edit/question/root'>{icon name=page_edit} Modifier la description</a>
-       {if $survey_editallmode}<br /><a href='survey/edit/add/0'>{icon name=add} Ajouter une question au d&#233;but</a>{/if}
+       {if $survey_editallmode}<br /><a href='survey/edit/add/0'>{icon name=add} Ajouter une question au début</a>{/if}
      </td>
      {/if}
    </tr>
@@@ -83,7 -83,7 +83,7 @@@
      <td class="smaller" style="width: 30%; vertical-align: middle">
        <a href='survey/edit/question/{$squestion.id}'>{icon name=page_edit} Modifier cette question</a><br />
        <a href='survey/edit/del/{$squestion.id}'>{icon name=delete} Supprimer cette question</a><br />
-       <a href='survey/edit/add/{$squestion.id+1}'>{icon name=add} Ajouter une question apr&#232;s</a>
+       <a href='survey/edit/add/{$squestion.id+1}'>{icon name=add} Ajouter une question après</a>
      </td>
      {/if}
    </tr>
  <p class="center">
    {if $survey_editmode}
    <a href='survey/edit/valid'>
 -    {icon name=tick} 
 +    {icon name=tick}
      {if $survey_updatemode}Enregistrer les modifications{else}Proposer ce sondage{/if}
    </a> |
    <a href='survey/edit/cancel'>
      {icon name=cross} Annuler
-     {if $survey_updatemode}les modifications{else}totalement la cr&#233;ation de ce sondage{/if}
+     {if $survey_updatemode}les modifications{else}totalement la création de ce sondage{/if}
    </a>
    {elseif $survey_adminmode}
    {if !$survey.valid}<a href="survey/admin/valid/{$survey.id}">Valider ce sondage</a> | {/if}