merge with master
authorPascal Corpet <pascal.corpet@m4x.org>
Tue, 22 Jul 2008 21:12:01 +0000 (23:12 +0200)
committerPascal Corpet <pascal.corpet@m4x.org>
Tue, 22 Jul 2008 21:12:01 +0000 (23:12 +0200)
24 files changed:
1  2 
htdocs/css/default.css
htdocs/xorg.php
include/notifs.inc.php
include/user.func.inc.php
include/userset.inc.php
modules/email.php
modules/geoloc.php
modules/marketing.php
modules/payment/money/paypal.inc.php
modules/profile.php
modules/profile/addresses.inc.php
modules/profile/general.inc.php
modules/profile/jobs.inc.php
modules/profile/page.inc.php
modules/search.php
modules/search/classes.inc.php
templates/core/vcard.tpl
templates/emails/redirect.tpl
templates/include/minifiche.tpl
templates/include/plview.referent.tpl
templates/include/plview.trombi.tpl
templates/marketing/private.tpl
templates/profile/profile.tpl
templates/search/adv.form.tpl

diff --combined htdocs/css/default.css
@@@ -107,10 -107,6 +107,10 @@@ p 
      background: inherit;
  }
  
 +.hinted {
 +    border-bottom: 1px dashed black;
 +}
 +
  input.error, textarea.error {
      background-color: #faa;
  }
@@@ -290,7 -286,7 +290,7 @@@ div.contact-list div.grayed 
  
  div.contact div.identity {
      float: left;
-     width: 90%;
+     width: 89%;
  }
  
  div.contact div.nom {
  div.contact div.bits {
      text-align: right;
      float: right;
+     width: 10%;
  }
  
  div.contact div.long {
  }
  
  div.long table { width: 100%; }
- div.long td.lt { width: 35%; font-style: italic; }
- div.long td.rt { width: 65%; }
+ div.long td.lt { width: 18%; font-style: italic; }
+ div.long td.rt { width: 82%; }
  
  /*******************************************************************************
      6   Profil
  }
  
  .wizard .wiz_header .wiz_tab {
-     background; url('../images/skins/wiz_normal.png') #aaa top left repeat-x;
+     background: url('../images/skins/wiz_normal.png') #aaa top left repeat-x;
      height: 100%;
      text-align: center;
      font-size: 75%;
diff --combined htdocs/xorg.php
   ***************************************************************************/
  
  require_once dirname(__FILE__).'/../include/xorg.inc.php';
- global $globals, $platal, $page;
  
  if (!($path = Env::v('n')) || ($path{0} < 'A' || $path{0} > 'Z')) {
      $platal = new Platal('auth', 'carnet', 'email', 'events', 'forums',
                           'geoloc', 'lists', 'marketing', 'payment', 'platal',
                           'profile', 'register', 'search', 'stats', 'admin',
                           'newsletter', 'axletter', 'bandeau', 'survey',
 +                         'fusionax',
                           'gadgets', 'googleapps');
      $platal->run();
      exit;
  }
  
diff --combined include/notifs.inc.php
@@@ -54,8 -54,7 +54,7 @@@ function register_watch_op($uid, $cid, 
                               WHERE  ni_id={?}', $uid);
          XDB::execute('DELETE FROM watch_nonins WHERE ni_id={?}', $uid);
      }
-     require_once 'xorg.misc.inc.php';
-     update_NbNotifs();
+     Platal::session()->updateNbNotifs();
  }
  
  // }}}
@@@ -144,7 -143,7 +143,7 @@@ $prf_desc = array('nom' => 'Son patrony
                    'mobile' => 'Son numéro de téléphone portable',
                    'nationalite' => 'Sa nationalité',
                    'nick' => 'Son surnom',
 -                  'web' => 'L\'adresse de son site web',
 +                  'networking' => 'La liste de ses adresses de networking',
                    'appli1' => 'Son école d\'application',
                    'appli2' => 'Son école de post-application',
                    'addresses' => 'Ses adresses',
@@@ -41,7 -41,7 +41,7 @@@ function user_clear_all_subs($user_id, 
                               'user_id' => array('requests', 'user_changes'));
  
      if ($really_del) {
 -        array_push($tables_to_clear['uid'], 'emails', 'groupex.membres', 'contacts', 'adresses', 'tels',
 +        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');
@@@ -87,8 -87,7 +87,7 @@@
  // Defaut callback to call when a login is not found
  function _default_user_callback($login)
  {
-     global $page;
-     $page->trigError("Il n'y a pas d'utilisateur avec l'identifiant : $login");
+     Platal::page()->trigError("Il n'y a pas d'utilisateur avec l'identifiant : $login");
      return;
  }
  
@@@ -99,7 -98,7 +98,7 @@@ function _silent_user_callback($login
  
  function get_user_login($data, $get_forlife = false, $callback = '_default_user_callback')
  {
-     global $globals, $page;
+     global $globals;
  
      if (is_numeric($data)) {
          $res = XDB::query("SELECT alias FROM aliases WHERE type='a_vie' AND id={?}", $data);
              default:
                  if (S::has_perms()) {
                      $aliases = $res->fetchColumn();
-                     $page->trigError("Il y a $i utilisateurs avec cette adresse mail : ".join(', ', $aliases));
+                     Platal::page()->trigError("Il y a $i utilisateurs avec cette adresse mail : ".join(', ', $aliases));
                  } else {
                      $res->free();
                  }
@@@ -198,15 -197,27 +197,27 @@@ function get_users_forlife_list($member
          if (strlen(trim($members)) == 0) {
              return null;
          }
-         $members = explode(' ', $members);
+         $members = split("[; ,\r\n\|]+", $members);
      }
      if ($members) {
          $list = array();
          foreach ($members as $i => $alias) {
+             $alias = trim($alias);
+             if (empty($alias)) {
+                 continue;
+             }
              if (($login = get_user_forlife($alias, $callback)) !== false) {
                  $list[$i] = $login;
-             } else if(!$strict) {
+             } else if (!$strict) {
                  $list[$i] = $alias;
+             } else {
+                 global $globals;
+                 if (strpos($alias, '@') !== false) {
+                     list($user, $dom) = explode('@', $alias);
+                     if ($dom != $globals->mail->domain && $dom != $globals->mail->domain2) {
+                         $list[$i] = $alias;
+                     }
+                 }
              }
          }
          return $list;
@@@ -247,7 -258,7 +258,7 @@@ function get_not_registered_user($login
      }
      $sql = "SELECT  user_id, nom, prenom, promo
                FROM  auth_user_md5
-              WHERE  $where
+              WHERE  $where AND perms = 'pending'
            ORDER BY  promo, nom, prenom";
      if ($iterator) {
          return XDB::iterator($sql, $nom, $prenom, $promo);
@@@ -264,8 -275,8 +275,8 @@@ function get_user_details_pro($uid, $vi
  {
      $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
 +                     gp.pays AS countrytxt, gr.name AS region, e.entrid,
 +                     e.pub, e.adr_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)
                      $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]);
          }
@@@ -347,7 -358,7 +358,7 @@@ function get_user_details_adr($uid, $vi
                       gp.pays AS countrytxt,a.region, a.regiontxt,
                       FIND_IN_SET('active', a.statut) AS active, a.adrid,
                       FIND_IN_SET('res-secondaire', a.statut) AS secondaire,
 -                     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)) {
@@@ -389,8 -401,8 +400,8 @@@ function &get_user_details($login, $fro
  {
      $reqsql = "SELECT  u.user_id, u.promo, u.promo_sortie, 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_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,
                         IF(gp.nat='',gp.pays,gp.nat) AS nationalite, gp.a2 AS iso3166,
                         a.alias AS forlife, a2.alias AS bestalias,
                         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
 +                       (COUNT(e.email) > 0 OR FIND_IN_SET('googleapps', u.mail_storage) > 0) AS actif,
 +                       nd.display AS name_display, nd.tooltip AS name_tooltip
                   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')
              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')
 +           INNER JOIN  profile_names_display AS nd ON (nd.user_id = u.user_id)
                  WHERE  a.alias = {?}
               GROUP BY  u.user_id";
      $res  = XDB::query($reqsql, $from_uid, $login);
          $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['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;
  }
  // }}}
@@@ -532,7 -527,7 +543,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 ++;
          }
      }
@@@ -550,17 -545,17 +561,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) {
 -    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()
@@@ -665,6 -646,13 +676,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) {
      $res = XDB::query("SELECT adrid FROM adresses WHERE uid = {?} AND adrid >= 1 ORDER BY adrid", $uid);
      $adrids = $res->fetchColumn();
@@@ -744,6 -714,9 +755,6 @@@ function set_user_details($uid, $detail
      if (isset($details['nom_usage'])) {
          XDB::execute("UPDATE auth_user_md5 SET nom_usage = {?} WHERE user_id = {?}", 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);
          }
      }
 +    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);
 +            }
 +        }
 +    }
 +
      // applis
      // medals
  }
diff --combined include/userset.inc.php
@@@ -19,7 -19,6 +19,6 @@@
   *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                *
   ***************************************************************************/
  
- require_once('xorg.misc.inc.php');
  require_once('user.func.inc.php');
  
  global $globals;
@@@ -164,11 -163,11 +163,11 @@@ class MinificheView extends MultipageVi
          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', '-promo', 'name_sort'), '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('name_sort'), 'nom');
 +        $this->addSortKey('promo', array('-promo', 'name_sort'), 'promotion');
 +        $this->addSortKey('date_mod', array('-date', '-promo', 'name_sort'), 'dernière modification');
          parent::__construct($set, $data, $params);
      }
  
                  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" .
 +                (COUNT(em.email) > 0 OR FIND_IN_SET('googleapps', u.mail_storage) > 0) AS actif,
 +                nd.display AS name_display, nd.tooltip AS name_tooltip, nd.sort AS name_sort" .
                  (S::logged() ? ", c.contact AS contact" : '');
      }
  
                                                        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  emails         AS em  ON (em.uid = u.user_id AND em.flags = 'active')" .
 +                 LEFT JOIN  emails         AS em  ON (em.uid = u.user_id AND em.flags = 'active')
 +                INNER JOIN  profile_names_display AS nd  ON (nd.user_id = u.user_id)" .
                  (S::logged() ?
                   "LEFT JOIN  contacts       AS c   On (c.contact = u.user_id AND c.uid = " . S::v('uid') . ")"
                   : "");
      }
  
+     public function bounds()
+     {
+         $order = Env::v('order', $this->defaultkey);
+         $show_bounds = 0;
+         if (($order == "name") || ($order == "-name")) {
+             $this->bound_field = "nom";
+             $show_bounds = 1;
+         } elseif (($order == "promo") || ($order == "-promo")) {
+             $this->bound_field = "promo";
+             $show_bounds = -1;
+         }
+         if ($order{0} == '-') {
+             $show_bounds = -$show_bounds;
+         }
+         return $show_bounds;
+     }
      public function templateName()
      {
          return 'include/plview.minifiche.tpl';
@@@ -223,25 -238,36 +239,42 @@@ 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('name_sort'), 'nom');
 +        $this->addSortKey('promo', array('-promo', 'name_sort'), 'promotion');
 +        $this->addSortKey('date_mod', array('-date', '-promo', 'name_sort'), 'dernière modification');
          parent::__construct($set, $data, $params);
      }
  
      public function fields()
      {
 -        return "m.uid, u.prenom, u.nom, u.promo,
 -                a.alias AS forlife, m.expertise, mp.pid,
 -                ms.secteur, ms.ss_secteur";
 +        return "m.uid, u.promo,
 +                a.alias AS bestalias, m.expertise, mp.pid,
 +                ms.secteur, ms.ss_secteur,
 +                nd.display AS name_display, nd.tooltip AS name_tooltip, nd.sort AS name_sort";
 +    }
 +
 +    public function joins()
 +    {
 +        return "INNER JOIN  profile_names_display AS nd ON (nd.user_id = u.user_id)";
      }
  
+     public function bounds()
+     {
+         $order = Env::v('order', $this->defaultkey);
+         $show_bounds = 0;
+         if (($order == "name") || ($order == "-name")) {
+             $this->bound_field = "nom";
+             $show_bounds = 1;
+         } elseif (($order == "promo") || ($order == "-promo")) {
+             $this->bound_field = "promo";
+             $show_bounds = -1;
+         }
+         if ($order{0} == '-') {
+             $show_bounds = -$show_bounds;
+         }
+         return $show_bounds;
+     }
      public function templateName()
      {
          return 'include/plview.referent.tpl';
@@@ -253,32 -279,48 +286,49 @@@ 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', 'name_sort'));
          if (@$params['with_score']) {
 -            $this->addSortKey('score', array('-score', '-watch_last', '-promo', 'nom', 'prenom'), 'pertinence');
 +            $this->addSortKey('score', array('-score', '-watch_last', '-promo', 'name_sort'), 'pertinence');
          }
 -        $this->addSortKey('name', array('nom', 'prenom'), 'nom');
 -        $this->addSortKey('promo', array('-promo', 'nom', 'prenom'), 'promotion');
 +        $this->addSortKey('name', array('name_sort'), 'nom');
 +        $this->addSortKey('promo', array('-promo', 'name_sort'), '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, a.alias AS forlife ";
 +        return "u.user_id, nd.display AS name_display, nd.tooltip AS name_tooltip, nd.sort AS name_sort, u.promo, a.alias AS forlife ";
      }
  
      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_names_display AS nd ON (nd.user_id = u.user_id)";
      }
  
+     public function bounds()
+     {
+         $order = Env::v('order', $this->defaultkey);
+         $show_bounds = 0;
+         if (($order == "name") || ($order == "-name")) {
+             $this->bound_field = "nom";
+             $show_bounds = 1;
+         } elseif (($order == "promo") || ($order == "-promo")) {
+             $this->bound_field = "promo";
+             $show_bounds = -1;
+         }
+         if ($order{0} == '-') {
+             $show_bounds = -$show_bounds;
+         }
+         return $show_bounds;
+     }
      public function templateName()
      {
          return 'include/plview.trombi.tpl';
      }
  
-     public function apply(PlatalPage &$page)
+     public function apply(PlPage &$page)
      {
          if (!empty($GLOBALS['IS_XNET_SITE'])) {
              global $globals;
@@@ -315,7 -357,7 +365,7 @@@ class GeolocView implements PlVie
          return $args;
      }
  
-     public function apply(PlatalPage &$page)
+     public function apply(PlPage &$page)
      {
          require_once 'geoloc.inc.php';
          require_once '../modules/search/search.inc.php';
@@@ -394,6 -436,7 +444,6 @@@ class GadgetView implements PlVie
      {
          return "u.user_id AS id,
                  u.*, a.alias AS forlife," .
 -                (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,
                   : "");
      }
  
-     public function apply(PlatalPage &$page)
+     public function apply(PlPage &$page)
      {
          $page->assign_by_ref('set',
            $this->set->get($this->fields(), $this->joins(), null, null, null, 5, 0));
diff --combined modules/email.php
@@@ -47,7 -47,7 +47,7 @@@ class EmailModule extends PLModul
          require_once 'emails.inc.php';
  
          $page->changeTpl('emails/index.tpl');
-         $page->assign('xorg_title','Polytechnique.org - Mes emails');
+         $page->setTitle('Polytechnique.org - Mes emails');
  
          $uid = S::v('uid');
  
@@@ -98,7 -98,7 +98,7 @@@
          global $globals;
  
          $page->changeTpl('emails/alias.tpl');
-         $page->assign('xorg_title','Polytechnique.org - Alias melix.net');
+         $page->setTitle('Polytechnique.org - Alias melix.net');
  
          $uid     = S::v('uid');
          $forlife = S::v('forlife');
              $actifs = Env::v('emails_actifs', Array());
              print_r(Env::v('emails_rewrite'));
              if (Env::v('emailop') == "ajouter" && Env::has('email')) {
 -                $page->assign('retour', $redirect->add_email(Env::v('email')));
 +                $new_email = Env::v('email');
 +                if ($new_email == "new@new.new") {
 +                    $new_email = Env::v('email_new');
 +                }
 +                $retour = $redirect->add_email($new_email);
 +                if ($retour == ERROR_INVALID_EMAIL) {
 +                    $page->assign('email', $new_email);
 +                }
 +                $page->assign('retour', $retour);
              } elseif (empty($actifs)) {
                  $page->assign('retour', ERROR_INACTIVE_REDIRECTION);
              } elseif (is_array($actifs)) {
  
          require_once 'googleapps.inc.php';
          $page->assign('googleapps', GoogleAppsAccount::account_status($uid));
 +
 +        require_once 'emails.combobox.inc.php';
 +        fill_email_combobox($page);
      }
  
      function handler_antispam(&$page, $statut_filtre = null)
              $mime = $upload->contentType();
              if ($mime != 'text/x-mail' && $mime != 'message/rfc822') {
                  $upload->clear();
-                 $page->trigError('Le fichier ne contient pas un mail complet');
+                 $page->trigError('Le fichier ne contient pas un email complet');
                  return;
              }
              global $globals;
          $page->changeTpl('emails/send.tpl');
          $page->addJsLink('ajax.js');
  
-         $page->assign('xorg_title','Polytechnique.org - Envoyer un email');
+         $page->setTitle('Polytechnique.org - Envoyer un email');
  
          // action si on recoit un formulaire
          if (Post::has('save')) {
                          $mymail->setWikiBody($txt);
                      }
                      if ($mymail->send()) {
-                         $page->trigSuccess("Ton mail a bien été envoyé.");
+                         $page->trigSuccess("Ton email a bien été envoyé.");
                          $_REQUEST = array('bcc' => S::v('bestalias').'@'.$globals->mail->domain);
                          PlUpload::clear(S::v('forlife'), 'emails.send');
                      } else {
                  // envoi du mail
                  $message = "Bonjour !
  
- Ce mail a été généré automatiquement par le service de patte cassée de
+ Cet email a été généré automatiquement par le service de patte cassée de
  Polytechnique.org car un autre utilisateur, ".S::v('prenom').' '.S::v('nom').",
- nous a signalé qu'en t'envoyant un mail, il avait reçu un message d'erreur
+ nous a signalé qu'en t'envoyant un email, il avait reçu un message d'erreur
  indiquant que ton adresse de redirection $email
  ne fonctionnait plus !
  
@@@ -556,7 -545,7 +556,7 @@@ L'équipe d'administration <support@" 
                  $mail->setSubject("Une de tes adresse de redirection Polytechnique.org ne marche plus !!");
                  $mail->setTxtBody($message);
                  $mail->send();
-                 $page->trigSuccess("Mail envoyé !");
+                 $page->trigSuccess("Email envoyé !");
              }
          } elseif (Post::has('email')) {
              S::assert_xsrf_token();
diff --combined modules/geoloc.php
@@@ -27,7 -27,6 +27,7 @@@ class GeolocModule extends PLModul
              'geoloc'             => $this->make_hook('default', AUTH_COOKIE),
              'admin/geoloc'           => $this->make_hook('admin', AUTH_MDP, 'admin'),
              'admin/geoloc/dynamap'   => $this->make_hook('admin_dynamap', AUTH_MDP, 'admin'),
 +            'admin/geoloc/country'   => $this->make_hook('admin_country',  AUTH_MDP, 'admin')
          );
      }
  
@@@ -43,7 -42,7 +43,7 @@@
      function handler_admin(&$page, $action = false) {
          $page->changeTpl('geoloc/admin.tpl');
          require_once("geoloc.inc.php");
-         $page->assign('xorg_title','Polytechnique.org - Administration - Geolocalisation');
+         $page->setTitle('Polytechnique.org - Administration - Geolocalisation');
  
          $nb_synchro = 0;
  
          $noCoordinates = $countNoCoordinates->fetchOneCell();
  
          if (isset($refresh) && $missing) {
-             $page->assign("xorg_extra_header", "<meta http-equiv='Refresh' content='3'/>");
+             $page->assign("pl_extra_header", "<meta http-equiv='Refresh' content='3'/>");
          }
          $page->assign("nb_cities_not_on_map", $missing);
          $page->assign("no_smallest", $noSmallest);
          $page->assign("no_coordinates", $noCoordinates);
      }
  
 +    function handler_admin_country(&$page, $action = 'list', $id = null)
 +    {
 +        $page->assign('xorg_title', 'Polytechnique.org - Administration - Pays');
 +        $page->assign('title', 'Gestion des pays');
 +        $table_editor = new PLTableEditor('admin/geoloc/country', 'geoloc_pays', 'a2', true);
 +        $table_editor->describe('a2', 'alpha-2', true);
 +        $table_editor->describe('a3', 'alpha-3', false);
 +        $table_editor->describe('n3', 'ISO numeric', false);
 +        $table_editor->describe('num', 'num', false);
 +        $table_editor->describe('worldrgn', 'Continent', false);
 +        $table_editor->describe('subd', 'Subdivisions territoriales', false);
 +        $table_editor->describe('post', 'post', false);
 +        $table_editor->describe('pays', 'Nom (fr)', true);
 +        $table_editor->describe('country', 'Nom (en)', true);
 +        $table_editor->describe('phoneprf', 'Préfixe téléphonique', true);
 +        $table_editor->describe('phoneformat', 'Format du téléphone (ex: (+p) ### ## ## ##)', false);
 +        $table_editor->describe('capital', 'Capitale', true);
 +        $table_editor->describe('nat', 'Nationalité', true);
 +        $table_editor->describe('display', 'Format des adresses', false);
 +
 +        if ($action == 'update') {
 +            if (Post::has('a2') && (Post::v('a2') == $id) && Post::has('phoneprf') && (Post::v('phoneprf') != '')) {
 +                if (Post::has('phoneformat')) {
 +                    $new_format = Post::v('phoneformat');
 +                } else {
 +                    $new_format = '';
 +                }
 +                $res = XDB::query("SELECT phoneformat
 +                                     FROM geoloc_pays
 +                                    WHERE phoneprf = {?}
 +                                    LIMIT 1",
 +                                  Post::v('phoneprf'));
 +                $old_format = $res->fetchOneCell();
 +                if ($new_format != $old_format) {
 +                    require_once("profil.func.inc.php");
 +                    XDB::execute("UPDATE  geoloc_pays
 +                                     SET  phoneformat = {?}
 +                                   WHERE  phoneprf = {?}",
 +                                 $new_format, Post::v('phoneprf'));
 +                }
 +            }
 +        }
 +        $table_editor->apply($page, $action, $id);
 +    }
 +
  }
  
  // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
diff --combined modules/marketing.php
@@@ -40,7 -40,7 +40,7 @@@ class MarketingModule extends PLModul
      {
          $page->changeTpl('marketing/index.tpl');
  
-         $page->assign('xorg_title','Polytechnique.org - Marketing');
+         $page->setTitle('Polytechnique.org - Marketing');
  
          // Quelques statistiques
  
          }
  
          if ($action == 'del') {
+             S::assert_xsrf_token();
              Marketing::clear($uid, $value);
          }
  
          }
  
          if ($action == 'relforce') {
+             S::assert_xsrf_token();
              $market = Marketing::get($uid, Post::v('to'));
              if (is_null($market)) {
                  $market = new Marketing($uid, Post::v('to'), 'default', null, 'staff');
              }
              $market->send(Post::v('title'), Post::v('message'));
-             $page->trigSuccess("Mail envoyé");
+             $page->trigSuccess("Email envoyé");
          }
  
          if ($action == 'insrel') {
+             S::assert_xsrf_token();
              if (Marketing::relance($uid)) {
                  $page->trigSuccess('relance faite');
              }
          $res = XDB::iterator(
                  "SELECT  r.*, a.alias
                     FROM  register_marketing AS r
 -             INNER JOIN  aliases            AS a ON (r.sender=a.id AND a.type = 'a_vie')
 +              LEFT JOIN  aliases            AS a ON (r.sender=a.id AND a.type = 'a_vie')
                    WHERE  uid={?}
                 ORDER BY  date", $uid);
          $page->assign('addr', $res);
              $email = valide_email(Post::v('mail'));
          }
          if (Post::has('valide') && isvalid_email_redirection($email)) {
+             S::assert_xsrf_token();
              // security stuff
              check_email($email, "Proposition d'une adresse surveillee pour " . $user['forlife'] . " par " . S::v('forlife'));
-             $res = XDB::query("SELECT  state
+             $res = XDB::query("SELECT  e.flags
                                   FROM  emails   AS e
                             INNER JOIN  aliases  AS a ON (a.id = e.uid)
                                  WHERE  e.email = {?} AND a.alias = {?}", $email, $user['forlife']);
              $page->assign('promo', $promo);
  
              if (Post::has('valide')) {
-                 require_once('xorg.misc.inc.php');
+                 S::assert_xstf_token();
                  $email = trim(Post::v('mail'));
  
                  if (!isvalid_email_redirection($email)) {
@@@ -80,17 -80,15 +80,16 @@@ class PayPa
          $res = XDB::query(
              "SELECT a.adr1 AS address1, a.adr2 AS address2,
                      a.city, a.postcode AS zip, a.country,
 -                    IF(t.tel, t.tel, q.profile_mobile) AS night_phone_b
 +                    IF(t1.display_tel != '', t1.display_tel, t2.display_tel) AS night_phone_b
                 FROM auth_user_quick AS q
            LEFT JOIN adresses  AS a ON (q.user_id = a.uid AND FIND_IN_SET('active', a.statut))
 -          LEFT JOIN tels        AS t ON (t.uid = a.uid AND t.adrid = a.adrid)
 +          LEFT JOIN profile_phones AS t1 ON (t1.uid = a.uid AND t1.link_type = 'address' AND t1.link_id = a.adrid)
 +          LEFT JOIN profile_phones AS t2 ON (t2.uid = a.uid AND t2.link_type = 'user' AND t2.link_id = 0)
                WHERE q.user_id = {?}
                LIMIT 1", S::v('uid'));
          $this->infos['client'] = array_map('replace_accent', array_merge($info_client, $res->fetchOneAssoc()));
  
          // on constuit la reference de la transaction
-         require_once 'xorg.misc.inc.php';
          $prefix = ($pay->flags->hasflag('unique')) ? str_pad("",15,"0") : rand_url_id();
          $fullref = substr("$prefix-xorg-{$pay->id}",-15);
  
diff --combined modules/profile.php
@@@ -35,11 -35,9 +35,11 @@@ class ProfileModule extends PLModul
              '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/networking'   => $this->make_hook('networking',   AUTH_PUBLIC),
              '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),
 +            'profile/ajax/searchname'   => $this->make_hook('ajax_searchname',   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),
@@@ -60,7 -58,6 +60,7 @@@
              '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/networking' => $this->make_hook('admin_networking', 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'),
          exit;
      }
  
 +    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;
          $page->changeTpl('profile/trombino.tpl');
  
          require_once('validations.inc.php');
                      .'/'.S::v('forlife').'.jpg';
  
          if (Env::has('upload')) {
+             S::assert_xsrf_token();
              $upload = new PlUpload(S::v('forlife'), 'photo');
              if (!$upload->upload($_FILES['userfile']) && !$upload->download(Env::v('photo'))) {
                  $page->trigError('Une erreur est survenue lors du téléchargement du fichier');
                  }
              }
          } elseif (Env::has('trombi')) {
+             S::assert_xsrf_token();
              $upload = new PlUpload(S::v('forlife'), 'photo');
              if ($upload->copyFrom($trombi_x)) {
                  $myphoto = new PhotoReq(S::v('uid'), $upload);
                  }
              }
          } elseif (Env::v('suppr')) {
+             S::assert_xsrf_token();
              XDB::execute('DELETE FROM  photo
                                  WHERE  uid = {?}',
                           S::v('uid'));
              XDB::execute('DELETE FROM  requests
                                  WHERE  user_id = {?} AND type="photo"',
                           S::v('uid'));
-             update_NbValid();
+             $globals->updateNbValid();
          } elseif (Env::v('cancel')) {
+             S::assert_xsrf_token();
              $sql = XDB::query('DELETE FROM  requests
                                       WHERE  user_id={?} AND type="photo"',
                                S::v('uid'));
-             update_NbValid();
+             $globals->updateNbValid();
          }
  
          $sql = XDB::query('SELECT  COUNT(*)
          }
  
          if (S::logged()) {
-             $_SESSION['log']->log('view_profile', $login);
+             S::logger()->log('view_profile', $login);
          }
  
          $title = $user['prenom'] . ' ' . ( empty($user['nom_usage']) ? $user['nom'] : $user['nom_usage'] );
-         $page->assign('xorg_title', $title);
+         $page->setTitle($title);
  
          // photo
  
               INNER JOIN auth_user_quick  ON ( user_id = {?} AND emails_alias_pub = 'public' )
                    WHERE ( redirect={?} OR redirect={?} )
                          AND alias LIKE '%@{$globals->mail->alias_dom}'",
-                 S::v('uid'),
+                 $user['user_id'],
                  $user['forlife'].'@'.$globals->mail->domain,
                  $user['forlife'].'@'.$globals->mail->domain2);
          $page->assign('virtualalias', $res->fetchOneCell());
                        . " la procédure de récupération de mot de passe si un jour tu le perdais");
          }
  
-        $page->assign('xorg_title', 'Polytechnique.org - Mon Profil');
+        $page->setTitle('Polytechnique.org - Mon Profil');
      }
  
      function handler_applis_js(&$page)
          $page->assign('adr', array());
      }
  
 -    function handler_ajax_tel(&$page, $adid, $telid)
 +    function handler_ajax_tel(&$page, $prefid, $prefname, $telid)
      {
          header('Content-Type: text/html; charset=utf-8');
 -        $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_searchname(&$page, $snid)
 +    {
 +        header('Content-Type: text/html; charset=utf-8');
 +        $page->changeTpl('profile/general.searchname.tpl', NO_SKIN);
 +        $page->assign('i', $snid);
 +        $page->assign('sn', array());
 +        $page->assign('newsn', true);
 +    }
 +    
      function handler_p_orange(&$page)
      {
          $page->changeTpl('profile/orange.tpl');
  
          require_once 'validations.inc.php';
-         require_once 'xorg.misc.inc.php';
  
          $res = XDB::query(
                  "SELECT  u.promo, u.promo_sortie
  
          if (!Env::has('promo_sortie')) {
              return;
+         } else {
+             S::assert_xsrf_token();
          }
  
          $promo_sortie = Env::i('promo_sortie');
      {
          require_once 'wiki.inc.php';
          wiki_require_page('Docs.Emploi');
-         $page->assign('xorg_title', 'Polytechnique.org - Conseil Pro');
+         $page->setTitle('Polytechnique.org - Conseil Pro');
  
          //recuperation des noms de secteurs
          $res = XDB::iterRow("SELECT id, label FROM emploi_secteur");
          $page->changeTpl('profile/nomusage.tpl');
  
          require_once 'validations.inc.php';
-         require_once 'xorg.misc.inc.php';
  
          $res = XDB::query(
                  "SELECT  u.nom, u.nom_usage, u.flags, e.alias
                    WHERE  user_id={?}", S::v('uid'));
  
          list($nom, $usage_old, $flags, $alias_old) = $res->fetchOneRow();
-         $flags = new flagset($flags);
+         $flags = new PlFlagSet($flags);
          $page->assign('usage_old', $usage_old);
          $page->assign('alias_old',  $alias_old);
  
          $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->assign('same', true);
      function handler_xnet(&$page)
      {
          $page->changeTpl('profile/groupesx.tpl');
-         $page->assign('xorg_title', 'Polytechnique.org - Promo, Groupes X, Binets');
+         $page->setTitle('Polytechnique.org - Promo, Groupes X, Binets');
  
          $req = XDB::query('
              SELECT m.asso_id, a.nom, diminutif, a.logo IS NOT NULL AS has_logo,
  
      function handler_admin_trombino(&$page, $uid = null, $action = null) {
          $page->changeTpl('profile/admin_trombino.tpl');
-         $page->assign('xorg_title','Polytechnique.org - Administration - Trombino');
+         $page->setTitle('Polytechnique.org - Administration - Trombino');
          $page->assign('uid', $uid);
  
          $q   = XDB::query(
          list($forlife, $promo) = $q->fetchOneRow();
  
          switch ($action) {
              case "original":
                  header("Content-type: image/jpeg");
                readfile("/home/web/trombino/photos".$promo."/".$forlife.".jpg");
                break;
  
              case "new":
+                 S::assert_xsrf_token();
                  $data = file_get_contents($_FILES['userfile']['tmp_name']);
                list($x, $y) = getimagesize($_FILES['userfile']['tmp_name']);
                $mimetype = substr($_FILES['userfile']['type'], 6);
                break;
  
              case "delete":
+                 S::assert_xsrf_token();
                  XDB::execute('DELETE FROM photo WHERE uid = {?}', $uid);
                  break;
          }
          $page->assign('forlife', $forlife);
      }
      function handler_admin_binets(&$page, $action = 'list', $id = null) {
-         $page->assign('xorg_title','Polytechnique.org - Administration - Binets');
+         $page->setTitle('Polytechnique.org - Administration - Binets');
          $page->assign('title', 'Gestion des binets');
          $table_editor = new PLTableEditor('admin/binets', 'binets_def', 'id');
          $table_editor->add_join_table('binets_ins','binet_id',true);
          $table_editor->apply($page, $action, $id);
      }
      function handler_admin_formations(&$page, $action = 'list', $id = null) {
-         $page->assign('xorg_title','Polytechnique.org - Administration - Formations');
+         $page->setTitle('Polytechnique.org - 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->apply($page, $action, $id);
      }
      function handler_admin_sections(&$page, $action = 'list', $id = null) {
-         $page->assign('xorg_title','Polytechnique.org - Administration - Sections');
+         $page->setTitle('Polytechnique.org - Administration - Sections');
          $page->assign('title', 'Gestion des sections');
          $table_editor = new PLTableEditor('admin/sections','sections','id');
          $table_editor->describe('text','intitulé',true);
          $table_editor->apply($page, $action, $id);
      }
      function handler_admin_ss_secteurs(&$page, $action = 'list', $id = null) {
-         $page->assign('xorg_title', 'Polytechnique.org - Administration - Sous-secteurs');
+         $page->setTitle('Polytechnique.org - 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);
          $table_editor->apply($page, $action, $id);
      }
      function handler_admin_fonctions(&$page, $action = 'list', $id = null) {
-         $page->assign('xorg_title', 'Polytechnique.org - Administration - Fonctions');
+         $page->setTitle('Polytechnique.org - 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->apply($page, $action, $id);
      }
      function handler_admin_secteurs(&$page, $action = 'list', $id = null) {
-         $page->assign('xorg_title', 'Polytechnique.org - Administration - Secteurs');
+         $page->setTitle('Polytechnique.org - Administration - Secteurs');
          $page->assign('title', 'Gestion des secteurs');
          $table_editor = new PLTableEditor('admin/secteurs', 'emploi_secteur', 'id', true);
          $table_editor->describe('label', 'intitulé', true);
          $table_editor->apply($page, $action, $id);
      }
 +    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_medals(&$page, $action = 'list', $id = null) {
-         $page->assign('xorg_title','Polytechnique.org - Administration - Distinctions');
+         $page->setTitle('Polytechnique.org - Administration - Distinctions');
          $page->assign('title', 'Gestion des Distinctions');
          $table_editor = new PLTableEditor('admin/medals','profile_medals','id');
          $table_editor->describe('text', 'intitulé',  true);
@@@ -23,24 -23,34 +23,24 @@@ class ProfileAddress extends ProfileGeo
  {
      private $bool;
      private $pub;
 -    private $tel;
  
      public function __construct()
      {
          $this->bool = new ProfileBool();
          $this->pub  = new ProfilePub();
 -        $this->tel  = new ProfileTel();
      }
  
 -    private function cleanAddress(ProfilePage &$page, array &$address, &$success)
 +    private function cleanAddress(ProfilePage &$page, $adrid, array &$address, &$success)
      {
          if (@$address['changed']) {
              $address['datemaj'] = time();
          }
          $success = true;
 -        foreach ($address['tel'] as $t=>&$tel) {
 -            if (@$tel['removed'] || !trim($tel['tel'])) {
 -                unset($address['tel'][$t]);
 -            } else {
 -                $tel['pub'] = $this->pub->value($page, 'pub', $tel['pub'], $s);
 -                $tel['tel'] = $this->tel->value($page, 'tel', $tel['tel'], $s);
 -                if (!$s) {
 -                    $tel['error'] = true;
 -                    $success = false;
 -                }
 -            }
 -            unset($tel['removed']);
 +        if (!isset($address['tel'])) {
 +            $address['tel'] = array();
          }
 +        $profiletel  = new ProfilePhones('address', $adrid);
 +        $address['tel'] = $profiletel->value($page, 'tel', $address['tel'], $s);
          $address['checked'] = $this->bool->value($page, 'checked', $address['checked'], $s);
          $address['secondaire'] = $this->bool->value($page, 'secondaire', $address['secondaire'], $s);
          $address['mail'] = $this->bool->value($page, 'mail', $address['mail'], $s);
@@@ -84,7 -94,7 +84,7 @@@
              $ls = true;
              $this->geolocAddress($adr, $s);
              $ls = ($ls && $s);
 -            $this->cleanAddress($page, $adr, $s);
 +            $this->cleanAddress($page, $key, $adr, $s);
              $ls = ($ls && $s);
              if (!trim($adr['text'])) {
                  unset($value[$key]);
  
      private function saveTel($adrid, $telid, array &$tel)
      {
 -        XDB::execute("INSERT INTO  tels (uid, adrid, telid,
 -                                         tel_type, tel_pub, tel)
 -                           VALUES  ({?}, {?}, {?},
 +        XDB::execute("INSERT INTO  profile_phones (uid, link_type, link_id, tel_id, tel_type,
 +                                              search_tel, display_tel, pub)
 +                           VALUES  ({?}, 'address', {?}, {?}, {?},
                                      {?}, {?}, {?})",
 -                    S::i('uid'), $adrid, $telid,
 -                    $tel['type'], $tel['pub'], $tel['tel']);
 +                    S::i('uid'), $adrid, $telid, $tel['type'],
 +                    format_phone_number($tel['tel']), $tel['tel'], $tel['pub']);
      }
  
      private function saveAddress($adrid, array &$address)
      {
-         $flags = array();
+         $flags = new PlFlagSet();
          if ($address['secondaire']) {
-             $flags[] = 'res-secondaire';
+             $flags->addFlag('res-secondaire');
          }
          if ($address['mail']) {
-             $flags[] = 'courrier';
+             $flags->addFlag('courrier');
          }
          if ($address['temporary']) {
-             $flags[] = 'temporaire';
+             $flags->addFlag('temporaire');
          }
          if ($address['current']) {
-             $flags[] = 'active';
+             $flags->addFlag('active');
          }
          if ($address['checked']) {
-             $flags[] = 'coord-checked';
+             $flags->addFlag('coord-checked');
          }
-         $flags = implode(',', $flags);
          XDB::execute("INSERT INTO  adresses (adr1, adr2, adr3,
                                                postcode, city, cityid,
                                                country, region, regiontxt,
                                                pub, datemaj, statut,
 -                                              uid, adrid, glat, glng)
 +                                              uid, adrid, glat, glng, comment)
                             VALUES  ({?}, {?}, {?},
                                      {?}, {?}, {?},
                                      {?}, {?}, {?},
                                      {?}, FROM_UNIXTIME({?}), {?},
 -                                    {?}, {?}, {?}, {?})",
 +                                    {?}, {?}, {?}, {?}, {?})",
                       $address['adr1'], $address['adr2'], $address['adr3'],
                       $address['postcode'], $address['city'], $address['cityid'],
                       $address['country'], $address['region'], $address['regiontxt'],
                       $address['pub'], $address['datemaj'], $flags,
 -                     S::i('uid'), $adrid, $address['precise_lat'], $address['precise_lon']);
 -        foreach ($address['tel'] as $telid=>&$tel) {
 -            $this->saveTel($adrid, $telid, $tel);
 -        }
 +                     S::i('uid'), $adrid, $address['precise_lat'], $address['precise_lon'], $address['comment']);
      }
  
      public function save(ProfilePage &$page, $field, $value)
          XDB::execute("DELETE FROM  adresses
                              WHERE  uid = {?}",
                       S::i('uid'));
 -        XDB::execute("DELETE FROM  tels
 -                            WHERE  uid = {?}",
 +        XDB::execute("DELETE FROM  profile_phones
 +                            WHERE  uid = {?} AND link_type = 'address'",
                       S::i('uid'));
          foreach ($value as $adrid=>&$address) {
              $this->saveAddress($adrid, $address);
 +            $profiletel = new ProfilePhones('address', $adrid);
 +            $profiletel->saveTels('tel', $address['tel']);
          }
      }
  }
@@@ -180,8 -190,7 +179,8 @@@ class ProfileAddresses extends ProfileP
                                     FIND_IN_SET('courrier', a.statut) AS mail,
                                     FIND_IN_SET('temporaire', a.statut) AS temporary,
                                     FIND_IN_SET('active', a.statut) AS current,
 -                                   a.glat AS precise_lat, a.glng AS precise_lon
 +                                   a.glat AS precise_lat, a.glng AS precise_lon,
 +                                   a.comment
                               FROM  adresses AS a
                         INNER JOIN  geoloc_pays AS gp ON(gp.a2 = a.country)
                              WHERE  uid = {?} AND NOT FIND_IN_SET('pro', statut)
              $this->values['addresses'] = $res->fetchAllAssoc();
          }
  
 -        $res = XDB::iterator("SELECT  adrid, tel_type AS type, tel_pub AS pub, tel
 -                                FROM  tels
 -                               WHERE  uid = {?}
 -                            ORDER BY  adrid",
 +        $res = XDB::iterator("SELECT  link_id AS adrid, tel_type AS type, pub, display_tel AS tel, comment
 +                                FROM  profile_phones
 +                               WHERE  uid = {?} AND link_type = 'address'
 +                            ORDER BY  link_id",
                               S::i('uid'));
          $i = 0;
          $adrNb = count($this->values['addresses']);
@@@ -52,9 -52,8 +52,8 @@@ class ProfileNom implements ProfileSett
                  || $this->matchWord($ini, $new, $newLen)
                  || ($field == 'nom' && $new == 'DE ' . $old);
          if (!$success) {
-             global $page;
-             $page->trigError("Le $field que tu as choisi ($value) est trop loin de ton $field initial ($init)"
-                        . (($init == $current)? "" : " et de ton prénom précédent ($current)"));
+             Platal::page()->trigError("Le $field que tu as choisi ($value) est trop loin de ton $field initial ($init)"
+                                     . (($init == $current)? "" : " et de ton prénom précédent ($current)"));
          }
          return $success ? $value : $current;
      }
      }
  }
  
 +class ProfileSearchName implements ProfileSetting
 +{
 +
 +    public function __construct()
 +    {
 +    }
 +
 +    public function value(ProfilePage &$page, $field, $value, &$success)
 +    {
 +    }
 +
 +    public function save(ProfilePage &$page, $field, $new_value)
 +    {
 +    }
 +}
 +
  class ProfileAppli implements ProfileSetting
  {
      public function value(ProfilePage &$page, $field, $value, &$success)
      }
  }
  
 +class ProfileEmailDirectory implements ProfileSetting
 +{
 +    private $email;
 +
 +    public function __construct()
 +    {
 +    }
 +
 +    public function value(ProfilePage &$page, $field, $value, &$success)
 +    {
 +        $p = $page;
 +        global $page;
 +
 +        $success = true;
 +        if (!is_null($value)) {
 +            $email_stripped = strtolower(trim($value));
 +            if ((!isvalid_email($email_stripped)) && ($email_stripped) && ($p->values['email_directory'] == "new@new.new")) {
 +                $page->assign('email_error', '1');
 +                $page->assign('email_directory_error', $email_stripped);
 +                $page->trigError('Adresse Email invalide');
 +                $success = false;
 +            } else {
 +                $page->assign('email_error', '0');
 +            }
 +        }
 +        return $value;
 +    }
 +
 +    public function save(ProfilePage &$page, $field, $value)
 +    {
 +    }
 +}
 +
 +class ProfileNetworking implements ProfileSetting
 +{
 +    private $email;
 +    private $pub;
 +    private $web;
 +    private $number;
 +
 +    public function __construct()
 +    {
 +        $this->email  = new ProfileEmail();
 +        $this->pub    = new ProfilePub();
 +        $this->web    = new ProfileWeb();
 +        $this->number = new ProfileNumber();
 +    }
 +
 +    public function value(ProfilePage &$page, $field, $value, &$success)
 +    {
 +        if (is_null($value)) {
 +            $value = array();
 +            $res = XDB::iterator("SELECT  n.address, n.network_type AS type, n.pub, m.name
 +                                    FROM  profile_networking AS n
 +                              INNER JOIN  profile_networking_enum AS m ON (n.network_type = m.network_type)
 +                                   WHERE  n.uid = {?}",
 +                                 S::i('uid'));
 +            while($network = $res->next()) {
 +                $value[] = $network;
 +            }
 +        }
 +        if (!is_array($value)) {
 +            $value = array();
 +        }
 +        $res = XDB::iterator("SELECT  filter, network_type AS type
 +                                FROM  profile_networking_enum;");
 +        $filters = array();
 +        while($filter = $res->next()) {
 +            $filters[$filter['type']] = $filter['filter'];
 +        }
 +        $success = true;
 +        foreach($value as $i=>&$network) {
 +            if (!trim($network['address'])) {
 +                unset($value[$i]);
 +            } else {
 +                if (!isset($network['pub'])) {
 +                    $network['pub'] = 'private';
 +                }
 +                $network['error'] = false;
 +                $network['pub'] = $this->pub->value($page, 'pub', $network['pub'], $s);
 +                $s = true;
 +                if ($filters[$network['type']] == 'web') {
 +                    $network['address'] = $this->web->value($page, 'address', $network['address'], $s);
 +                } elseif ($filters[$network['type']] == 'email') {
 +                    $network['address'] = $this->email->value($page, 'address', $network['address'], $s);
 +                } elseif ($filters[$network['type']] == 'number') {
 +                    $network['address'] = $this->number->value($page, 'address', $network['address'], $s);
 +                }
 +                if (!$s) {
 +                    $success = false;
 +                    $network['error'] = true;
 +                }
 +            }
 +        }
 +        return $value;
 +    }
 +
 +    public function save(ProfilePage &$page, $field, $value)
 +    {
 +        XDB::execute("DELETE FROM profile_networking
 +                            WHERE uid = {?}",
 +                     S::i('uid'));
 +        if (!count($value)) {
 +            return;
 +        }
 +        $insert = array();
 +        foreach ($value as $id=>$network) {
 +            XDB::execute("INSERT INTO  profile_networking (uid, nwid, network_type, address, pub)
 +                               VALUES  ({?}, {?}, {?}, {?}, {?})",
 +                         S::i('uid'), $id, $network['type'], $network['address'], $network['pub']);
 +        }
 +    }
 +}
 +
  class ProfileGeneral extends ProfilePage
  {
      protected $pg_template = 'profile/general.tpl';
      public function __construct(PlWizard &$wiz)
      {
          parent::__construct($wiz);
 -        $this->settings['nom'] = $this->settings['prenom']
 -                               = new ProfileNom();
 +        $this->settings['nom']    = $this->settings['prenom']
 +                                  = new ProfileNom();
          $this->settings['naissance'] = new ProfileDate();
 -        $this->settings['mobile_pub']
 -                                  = $this->settings['web_pub']
 -                                  = $this->settings['freetext_pub']
 +        $this->settings['freetext_pub']
                                    = $this->settings['photo_pub']
                                    = new ProfilePub();
          $this->settings['freetext']
                                    = $this->settings['nationalite']
                                    = $this->settings['nick']
 +                                  = $this->settings['yourself']
 +                                  = $this->settings['display_name']
 +                                  = $this->settings['sort_name']
 +                                  = $this->settings['tooltip_name']
                                    = null;
          $this->settings['synchro_ax']
                                    = new ProfileBool();
 -        $this->settings['mobile'] = new ProfileTel();
 -        $this->settings['web'] = new ProfileWeb();
 +        $this->settings['email_directory']
 +                                  = new ProfileEmail();
 +        $this->settings['email_directory_new']
 +                                  = new ProfileEmailDirectory();
 +        $this->settings['networking'] = new ProfileNetworking();
 +        $this->settings['tels'] = new ProfilePhones('user', 0);
          $this->settings['appli1']
                                    = $this->settings['appli2']
                                    = new ProfileAppli();
 -        $this->watched= array('nom' => true, 'freetext' => true, 'mobile' => true, 'web' => true,
 -                       'appli1' => true, 'appli2' => true, 'nationalite' => true, 'nick' => true);
 +        $this->watched= array('nom' => true, 'freetext' => true, 'tels' => true,
 +                              'networking' => true, 'appli1' => true, 'appli2' => true,
 +                              'nationalite' => true, 'nick' => true);
      }
  
      protected function _fetchData()
      {
          // Checkout all data...
          $res = XDB::query("SELECT  u.promo, u.promo_sortie, u.nom_usage, u.nationalite, u.naissance,
 -                                   q.profile_mobile as mobile, q.profile_mobile_pub as mobile_pub,
 -                                   q.profile_web as web, q.profile_web_pub as web_pub,
 +                                   t.display_tel as mobile, t.pub as mobile_pub,
 +                                   d.email_directory as email_directory,
                                     q.profile_freetext as freetext, q.profile_freetext_pub as freetext_pub,
                                     q.profile_nick as nick, q.profile_from_ax as synchro_ax, u.matricule_ax,
                                     IF(a1.aid IS NULL, -1, a1.aid) as appli_id1, a1.type as appli_type1,
 -                                   IF(a2.aid IS NULL, -1, a2.aid) as appli_id2, a2.type as appli_type2
 -                             FROM  auth_user_md5   AS u
 -                       INNER JOIN  auth_user_quick AS q  USING(user_id)
 -                        LEFT JOIN  applis_ins      AS a1 ON(a1.uid = u.user_id and a1.ordre = 0)
 -                        LEFT JOIN  applis_ins      AS a2 ON(a2.uid = u.user_id and a2.ordre = 1)
 +                                   IF(a2.aid IS NULL, -1, a2.aid) as appli_id2, a2.type as appli_type2,
 +                                   n.yourself, n.display AS display_name, n.sort AS sort_name,
 +                                   n.tooltip AS tooltip_name
 +                             FROM  auth_user_md5         AS u
 +                       INNER JOIN  auth_user_quick       AS q  ON(u.user_id = q.user_id)
 +                       INNER JOIN  profile_names_display AS n  ON(n.user_id = u.user_id)
 +                        LEFT JOIN  profile_phones        AS t  ON(u.user_id = t.uid AND link_type = 'user')
 +                        LEFT JOIN  profile_directory     AS d  ON(d.uid = u.user_id)
 +                        LEFT JOIN  applis_ins            AS a1 ON(a1.uid = u.user_id and a1.ordre = 0)
 +                        LEFT JOIN  applis_ins            AS a2 ON(a2.uid = u.user_id and a2.ordre = 1)
                              WHERE  u.user_id = {?}", S::v('uid', -1));
          $this->values = $res->fetchOneAssoc();
  
                              WHERE  type='photo' AND user_id = {?}",
                            S::v('uid'));
          $this->values['nouvellephoto'] = $res->fetchOneCell();
 +
 +        // Retreive search names info
 +        $this->values['search_names'] = XDB::iterator("
 +                              SELECT  sn.search_name, sn.name_type, sn.pub, sn.sn_id
 +                                FROM  profile_names_search AS sn
 +                               WHERE  sn.user_id = {?}
 +                            ORDER BY  sn.name_type, search_score, search_name",
 +                          S::v('uid'));
 +
 +        // Retreive phones
 +        $res = XDB::iterator("SELECT t.display_tel AS tel, t.tel_type AS type, t.pub, t.comment
 +                                FROM profile_phones AS t
 +                               WHERE t.uid = {?} AND t.link_type = 'user'
 +                            ORDER BY t.tel_id",
 +                             S::v('uid'));
 +        $this->values['tels'] = $res->fetchAllAssoc();
      }
  
      protected function _saveData()
                           preg_replace('@(\d{2})/(\d{2})/(\d{4})@', '\3-\2-\1', $this->values['naissance']),
                           S::v('uid'));
          }
 -        if ($this->changed['nick'] || $this->changed['mobile'] || $this->changed['mobile_pub']
 -            || $this->changed['web'] || $this->changed['web_pub'] || $this->changed['freetext']
 -            || $this->changed['freetext_pub'] || $this->changed['synchro_ax']) {
 +        if ($this->changed['nick'] || $this->changed['freetext'] || $this->changed['freetext_pub'] || $this->changed['synchro_ax']) {
              XDB::execute("UPDATE  auth_user_quick
 -                             SET  profile_nick= {?}, profile_mobile={?}, profile_mobile_pub={?}, 
 -                                  profile_web={?}, profile_web_pub={?}, profile_freetext={?}, 
 +                             SET  profile_nick= {?},
 +                                  profile_freetext={?},
                                    profile_freetext_pub={?}, profile_from_ax = {?} 
                             WHERE  user_id = {?}", 
 -                         $this->values['nick'], $this->values['mobile'], $this->values['mobile_pub'],
 -                         $this->values['web'], $this->values['web_pub'],
 +                         $this->values['nick'],
                           $this->values['freetext'], $this->values['freetext_pub'],
                           $this->values['synchro_ax'], S::v('uid'));
          }
 +        if ($this->changed['email_directory']) {
 +            $new_email = ($this->values['email_directory'] == "new@new.new") ?
 +                $this->values['email_directory_new'] : $this->values['email_directory'];
 +            XDB::execute("REPLACE INTO  profile_directory (uid, email_directory)
 +                                VALUES  ({?}, {?})",
 +                         S::v('uid'), $new_email);
 +        }
          if ($this->changed['nick']) {
              require_once('user.func.inc.php');
              user_reindex(S::v('uid'));
                             WHERE  uid = {?}",
                           $this->values['photo_pub'], S::v('uid'));
          }
 +        if ($this->changed['yourself'] || $this->changed['sort_name'] ||
 +            $this-> changed['display_name'] || $this->changed['tooltip_name']) {
 +          XDB::execute("UPDATE  profile_names_display AS n
 +                           SET  n.yourself = {?},
 +                                n.sort = {?}, ". // SET
 +                               "n.display = {?}, ". // SET
 +                               "n.tooltip = {?} ". // SET
 +                        "WHERE  n.user_id = {?}",
 +                       $this->values['yourself'],
 +                       $this->values['sort_name'],
 +                       $this->values['display_name'],
 +                       $this->values['tooltip_name'],
 +                        S::v('uid'));
 +        }
      }
  
-     public function _prepare(PlatalPage &$page, $id)
+     public function _prepare(PlPage &$page, $id)
      {
          require_once "applis.func.inc.php";
 +
 +        require_once "emails.combobox.inc.php";
 +        fill_email_combobox($page);
 +
 +        $res = XDB::iterator("SELECT  nw.network_type AS type, nw.name
 +                                FROM  profile_networking_enum AS nw
 +                            ORDER BY  name");
 +        $page->assign('network_list', $res->fetchAllAssoc());
      }
  }
  
  class ProfileJob extends ProfileGeoloc
  {
      private $pub;
 +    private $mail_new;
      private $mail;
      private $web;
 -    private $tel;
      private $bool;
      private $checks;
  
      public function __construct()
      {
          $this->pub  = new ProfilePub();
 -        $this->mail = new ProfileEmail();
 +        $this->mail
 +                    = $this->mail_new
 +                    = new ProfileEmail();
          $this->web  = new ProfileWeb();
 -        $this->tel  = new ProfileTel();
          $this->bool = new ProfileBool();
          $this->checks = array('web' => array('web'),
 +                              'mail_new' => array('email_new'),
                                'mail' => array('email'),
 -                              'tel' => array('tel', 'fax', 'mobile'),
 -                              'pub' => array('pub', 'tel_pub', 'email_pub'));
 +                              'pub' => array('pub', 'email_pub'));
      }
  
 -    private function cleanJob(ProfilePage &$page, array &$job, &$success)
 +    private function cleanJob(ProfilePage &$page,$jobid, array &$job, &$success)
      {
          $success = true;
          foreach ($this->checks as $obj=>&$fields) {
              $chk =& $this->$obj;
              foreach ($fields as $field) {
 +                if ($field == "email_new") {
 +                    if ($job['email'] == "new@new.new") {
 +                        $job['email'] = $job[$field];
 +                    }
 +                    continue;
 +                }
                  $job[$field] = $chk->value($page, $field, $job[$field], $s);
                  if (!$s) {
                      $success = false;
          }
          $job['adr']['pub'] = $this->pub->value($page, 'adr_pub', @$job['adr']['pub'], $s);
          $job['adr']['checked'] = $this->bool->value($page, 'adr_checked', @$job['adr']['checked'], $s);
 +        if (!isset($job['tel'])) {
 +            $job['tel'] = array();
 +        }
 +        $profiletel = new ProfilePhones('pro', $jobid);
 +        $job['tel'] = $profiletel->value($page, 'tel', $job['tel'], $s);
          unset($job['removed']);
          unset($job['new']);
          unset($job['adr']['changed']);
@@@ -92,7 -80,7 +92,7 @@@
              $ls = true;
              $this->geolocAddress($job['adr'], $s);
              $ls = ($ls && $s);
 -            $this->cleanJob($page, $job, $s);
 +            $this->cleanJob($page, $key, $job, $s);
              $ls = ($ls && $s);
              if (!$init) {
                  $success = ($success && $ls);
  
      public function save(ProfilePage &$page, $field, $value)
      {
 +        require_once('profil.func.inc.php');
          XDB::execute("DELETE FROM  entreprises
                              WHERE  uid = {?}",
                       S::i('uid'));
 +        XDB::execute("DELETE FROM  profile_phones
 +                            WHERE  uid = {?} AND link_type = 'pro'",
 +                     S::i('uid'));
          $i = 0;
 -        foreach ($value as &$job) {
 +        foreach ($value as $jobid=>&$job) {
 +            if ($job['email'] == "new@new.new") {
 +                $job['email'] = $job['email_new'];
 +            }
              XDB::execute("INSERT INTO  entreprises (uid, entrid, entreprise, secteur, ss_secteur,
                                                      fonction, poste, adr1, adr2, adr3, postcode,
                                                      city, cityid, country, region, regiontxt,
 -                                                    tel, fax, mobile, email, web,
 -                                                    pub, adr_pub, tel_pub, email_pub, flags,
 +                                                    email, web,
 +                                                    pub, adr_pub, email_pub, flags,
                                                      glat, glng)
                                 VALUES  ({?}, {?}, {?}, {?}, {?},
                                          {?}, {?}, {?}, {?}, {?}, {?},
                                          {?}, {?}, {?}, {?}, {?},
 -                                        {?}, {?}, {?}, {?}, {?},
 -                                        {?}, {?}, {?}, {?}, {?},
 +                                        {?}, {?},
 +                                        {?}, {?}, {?}, {?},
                                          {?}, {?})",
 -                         S::i('uid'), $i++, $job['name'], $job['secteur'], $job['ss_secteur'],
 +                         S::i('uid'), $i, $job['name'], $job['secteur'], $job['ss_secteur'],
                           $job['fonction'], $job['poste'], $job['adr']['adr1'], $job['adr']['adr2'], $job['adr']['adr3'],
                           $job['adr']['postcode'],
                           $job['adr']['city'], $job['adr']['cityid'], $job['adr']['country'], $job['adr']['region'], 
                           $job['adr']['regiontxt'],
 -                         $job['tel'], $job['fax'], $job['mobile'], $job['email'], $job['web'],
 -                         $job['pub'], $job['adr']['pub'], $job['tel_pub'], $job['email_pub'],
 +                         $job['email'], $job['web'],
 +                         $job['pub'], $job['adr']['pub'], $job['email_pub'],
                           $job['adr']['checked'] ? 'geoloc' : '', $job['adr']['precise_lat'],
                           $job['adr']['precise_lon']);
 +            $profiletel = new ProfilePhones('pro', $jobid);
 +            $profiletel->saveTels('tel', $job['tel']);
 +            $i++;
          }
      }
  }
@@@ -165,27 -143,25 +165,27 @@@ class ProfileJobs extends ProfilePag
          $this->values['cv'] = $res->fetchOneCell();
  
          // Build the jobs tree
 -        $res = XDB::iterRow("SELECT  e.entreprise, e.secteur, e.ss_secteur,
 +        $res = XDB::iterRow("SELECT  e.entrid, e.entreprise, e.secteur, e.ss_secteur,
                                       e.fonction, e.poste, e.adr1, e.adr2, e.adr3,
                                       e.postcode, e.city, e.cityid, e.region, e.regiontxt,
                                       e.country, gp.pays, gp.display,
                                       FIND_IN_SET('geoloc', flags),
 -                                     e.tel, e.fax, e.mobile, e.email, e.web, e.pub,
 -                                     e.adr_pub, e.tel_pub, e.email_pub,
 +                                     e.email, e.web, e.pub,
 +                                     e.adr_pub, e.email_pub,
                                       e.glat AS precise_lat, e.glng AS precise_lon
                                 FROM  entreprises AS e
                            LEFT JOIN  geoloc_pays AS gp ON(gp.a2 = e.country)
 -                              WHERE  uid = {?} AND entreprise != ''
 +                              WHERE  e.uid = {?} AND entreprise != ''
                             ORDER BY  entrid", S::i('uid'));
          $this->values['jobs'] = array();
 -        while (list($name, $secteur, $ss_secteur, $fonction, $poste,
 +        while (list($id, $name, $secteur, $ss_secteur, $fonction, $poste,
                      $adr1, $adr2, $adr3, $postcode, $city, $cityid,
                      $region, $regiontxt, $country, $countrytxt, $display,
 -                    $checked, $tel, $fax, $mobile, $email, $web,
 -                    $pub, $adr_pub, $tel_pub, $email_pub, $glat, $glng) = $res->next()) {
 -            $this->values['jobs'][] = array('name'       => $name,
 +                    $checked, $email, $web,
 +                    $pub, $adr_pub, $email_pub, $glat, $glng
 +                   ) = $res->next()) {
 +            $this->values['jobs'][] = array('id'         => $id,
 +                                            'name'       => $name,
                                              'secteur'    => $secteur,
                                              'ss_secteur' => $ss_secteur,
                                              'fonction'   => $fonction,
                                                                    'checked'    => $checked,
                                                                    'precise_lat'=> $glat,
                                                                    'precise_lon'=> $glng),
 -                                            'tel'        => $tel,
 -                                            'fax'        => $fax,
 -                                            'mobile'     => $mobile,
                                              'email'      => $email,
                                              'web'        => $web,
                                              'pub'        => $pub,
 -                                            'tel_pub'    => $tel_pub,
                                              'email_pub'  => $email_pub);
          }
 +
 +        $res = XDB::iterator("SELECT  link_id AS jobid, tel_type AS type, pub, display_tel AS tel, comment
 +                                FROM  profile_phones
 +                               WHERE  uid = {?} AND link_type = 'pro'
 +                            ORDER BY  link_id",
 +                             S::i('uid'));
 +        $i = 0;
 +        $jobNb = count($this->values['jobs']);
 +        while ($tel = $res->next()) {
 +            $jobid = $tel['jobid'];
 +            unset($tel['jobid']);
 +            while ($i < $jobNb && $this->values['jobs'][$i]['id'] < $jobid) {
 +                $i++;
 +            }
 +            if ($i >= $jobNb) {
 +                break;
 +            }
 +            $job =& $this->values['jobs'][$i];
 +            if (!isset($job['tel'])) {
 +                $job['tel'] = array();
 +            }
 +            if ($job['id'] == $jobid) {
 +                $job['tel'][] = $tel;
 +            }
 +        }
 +        foreach ($this->values['jobs'] as $id=>&$job) {
 +            if (!isset($job['tel'])) {
 +                $job['tel'] = array();
 +            }
 +            unset($job['id']);
 +        }
      }
  
      protected function _saveData()
          }
      }
  
-     public function _prepare(PlatalPage &$page, $id)
+     public function _prepare(PlPage &$page, $id)
      {
 +        require_once "emails.combobox.inc.php";
 +        fill_email_combobox($page);
 +
          $page->assign('secteurs', XDB::iterator("SELECT  id, label
                                                     FROM  emploi_secteur"));
          $page->assign('fonctions', XDB::iterator("SELECT  id, fonction_fr, FIND_IN_SET('titre', flags) AS title
@@@ -53,9 -53,8 +53,8 @@@ class ProfileWeb extends ProfileNoSav
          $value = trim($value);
          $success = empty($value) || preg_match("{^(https?|ftp)://[a-zA-Z0-9._%#+/?=&~-]+$}i", $value);
          if (!$success) {
-             global $page;
-             $page->trigError('URL Incorrecte : une url doit commencer par http:// ou https:// ou ftp://'
-                       . ' et ne pas contenir de caractères interdits');
+             Platal::page()->trigError('URL Incorrecte : une url doit commencer par http:// ou https:// ou ftp://'
+                                     . ' et ne pas contenir de caractères interdits');
          }
          return $value;
      }
@@@ -69,33 -68,14 +68,31 @@@ class ProfileEmail extends ProfileNoSav
              return isset($page->values[$field]) ? $page->values[$field] : S::v($field);
          }
          $value = trim($value);
-         require_once 'xorg.misc.inc.php';
          $success = empty($value) || isvalid_email($value);
          if (!$success) {
-             global $page;
-             $page->trigError('Adresse Email invalide');
+             Platal::page()->trigError('Adresse Email invalide');
          }
          return $value;
      }
  }
  
 +class ProfileNumber extends ProfileNoSave
 +{
 +    public function value(ProfilePage &$page, $field, $value, &$success)
 +    {
 +        if (is_null($value)) {
 +            return isset($page->values[$field]) ? $page->values[$field] : S::v($field);
 +        }
 +        $value = trim($value);
 +        $success = empty($value) || is_numeric($value);
 +        if (!$success) {
 +            global $page;
 +            $page->trigError('Numéro invalide');
 +        }
 +        return $value;
 +    }
 +}
 +
  
  class ProfileTel extends ProfileNoSave
  {
          if (is_null($value)) {
              return isset($page->values[$field]) ? $page->values[$field] : S::v($field);
          }
 -        $success = !preg_match('/[<>{}@&#~\/:;?,!§*_`\[\]|%$^=]/', $value, $matches);
 +        require_once('profil.func.inc.php');
 +        $value = format_phone_number($value);
 +        if($value == '') {
 +            $success = true;
 +            return $value;
 +        }
 +        $value = format_display_number($value,$error);
 +        $success = !$error;
          if (!$success) {
 -            Platal::page()->trigError('Le numéro de téléphone contient un caractère interdit : ' . pl_entities($matches[0][0]));
 +            global $page;
 +            $page->trigError('Le préfixe international du numéro de téléphone est inconnu. ');
          }
          return $value;
      }
  }
  
 +class ProfilePhones implements ProfileSetting
 +{
 +    private $tel;
 +    private $pub;
 +    protected $link_type;
 +    protected $link_id;
 +
 +    public function __construct($type, $id)
 +    {
 +        $this->tel = new ProfileTel();
 +        $this->pub = new ProfilePub();
 +        $this->link_type = $type;
 +        $this->link_id = $id;
 +    }
 +
 +    public function value(ProfilePage &$page, $field, $value, &$success)
 +    {
 +        $success = true;
 +        if (is_null($value)) {
 +            $value = isset($page->values[$field]) ? $page->values[$field] : array();
 +        }
 +        if (!is_array($value)) {
 +            $value = array();
 +        }
 +        foreach ($value as $key=>&$phone) {
 +            if (@$phone['removed']) {
 +                unset($value[$key]);
 +            } else {
 +                $phone['pub'] = $this->pub->value($page, 'pub', $phone['pub'], $s);
 +                $phone['tel'] = $this->tel->value($page, 'tel', $phone['tel'], $s);
 +                if(!isset($phone['type']) || ($phone['type'] != 'fixed' && $phone['type'] != 'mobile' && $phone['type'] != 'fax')) {
 +                    $phone['type'] = 'fixed';
 +                    $s = false;
 +                }
 +                if (!$s) {
 +                    $phone['error'] = true;
 +                    $success = false;
 +                }
 +                if (!isset($phone['comment'])) {
 +                    $phone['comment'] = '';
 +                }
 +            }
 +        }
 +        return $value;
 +    }
 +
 +    private function saveTel($telid, array &$phone)
 +    {
 +        if ($phone['tel'] != '') {
 +            XDB::execute("INSERT INTO  profile_phones (uid, link_type, link_id, tel_id, tel_type,
 +                                       search_tel, display_tel, pub, comment)
 +                               VALUES  ({?}, {?}, {?}, {?}, {?},
 +                                       {?}, {?}, {?}, {?})",
 +                         S::i('uid'), $this->link_type, $this->link_id, $telid, $phone['type'],
 +                        format_phone_number($phone['tel']), $phone['tel'], $phone['pub'], $phone['comment']);
 +        }
 +    }
 +
 +    public function save(ProfilePage &$page, $field, $value)
 +    {
 +        XDB::execute("DELETE FROM  profile_phones
 +                            WHERE  uid = {?} AND link_type = {?} AND link_id = {?}",
 +                            S::i('uid'), $this->link_type, $this->link_id);
 +        $this->saveTels($field, $value);
 +    }
 +
 +    //Only saves phones without a delete operation
 +    public function saveTels($field, $value)
 +    {
 +        foreach ($value as $telid=>&$phone) {
 +            $this->saveTel($telid, $phone);
 +        }
 +    }
 +}
 +
  class ProfilePub extends ProfileNoSave
  {
      public function value(ProfilePage &$page, $field, $value, &$success)
@@@ -234,16 -131,14 +231,14 @@@ class ProfileDate extends ProfileNoSav
          } else {
              $success = preg_match('@(\d{2})/(\d{2})/(\d{4})@', $value, $matches);
              if (!$success) {
-                 global $page;
-                 $page->trigError("Les dates doivent être au format jj/mm/aaaa");
+                 Platal::page()->trigError("Les dates doivent être au format jj/mm/aaaa");
             } else {
                  $day   = (int)$matches[1];
                  $month = (int)$matches[2];
                  $year  = (int)$matches[3];
                  $success = ($day > 0 && $day <= 31) && ($month > 0 && $month <= 12) && ($year > 1900 && $year <= 2020);
                  if (!$success) {
-                     global $page;
-                     $page->trigError("La date n'a pas une valeur valide");
+                     Platal::page()->trigError("La date n'a pas une valeur valide");
                  }
              }
          }
@@@ -359,7 -254,7 +354,7 @@@ abstract class ProfilePage implements P
          }
          global $platal;
          $log =& $_SESSION['log'];
-         $log->log('profil', $platal->pl_self(1));
+         S::logger()->log('profil', $platal->pl_self(1));
      }
  
      protected function checkChanges()
          return 'profile/base.tpl';
      }
  
-     protected function _prepare(PlatalPage &$page, $id)
+     protected function _prepare(PlPage &$page, $id)
      {
      }
  
-     public function prepare(PlatalPage &$page, $id)
+     public function prepare(PlPage &$page, $id)
      {
          if (count($this->values) == 0) {
              $this->fetchData();
              }
              return Post::has('next_page') ? PlWizard::NEXT_PAGE : PlWizard::CURRENT_PAGE;
          }
-         global $page;
-         $page->trigError("Certains champs n'ont pas pu être validés, merci de corriger les informations "
-                   . "de ton profil et de revalider ta demande");
+         Platal::page()->trigError("Certains champs n'ont pas pu être validés, merci de corriger les informations "
+                                 . "de ton profil et de revalider ta demande");
          return PlWizard::CURRENT_PAGE;
      }
  }
diff --combined modules/search.php
@@@ -47,9 -47,7 +47,7 @@@ class SearchModule extends PLModul
  
      function form_prepare()
      {
-         global $page;
-         $page->assign('formulaire',1);
+         Platal::page()->assign('formulaire',1);
      }
  
      function get_diplomas($school = null)
@@@ -72,8 -70,7 +70,7 @@@
              $types = explode('(',$row[1]);
              $types = str_replace("'","",substr($types[1],0,-1));
          }
-         global $page;
-         $page->assign('choix_diplomas', explode(',',$types));
+         Platal::page()->assign('choix_diplomas', explode(',',$types));
      }
  
      function handler_quick(&$page, $action = null, $subaction = null)
@@@ -90,7 -87,7 +87,7 @@@
          if (Env::has('quick') || $action == 'geoloc') {
              $quick = trim(Env::v('quick'));
              if (S::logged() && !Env::has('page')) {
-                 $_SESSION['log']->log('search', 'quick=' . $quick);
+                 S::logger()->log('search', 'quick=' . $quick);
              }
              $list = 'profile|prf|fiche|fic|referent|ref|mentor';
              if (S::has_perms()) {
  
              require_once 'userset.inc.php';
              $view = new SearchSet(true, $action == 'geoloc' && substr($subaction, -3) == 'swf');
-             $view->addMod('minifiche', 'Minifiches', true, array('with_score' => true));
+             $view->addMod('minifiche', 'Mini-fiches', true, array('with_score' => true));
              if (S::logged() && !Env::i('nonins')) {
                  $view->addMod('trombi', 'Trombinoscope', false, array('with_promo' => true, 'with_score' => true));
                  $view->addMod('geoloc', 'Planisphère', false, array('with_annu' => 'search/adv'));
  
          require_once dirname(__FILE__) . '/search/search.inc.php';
          $page->changeTpl('search/index.tpl');
-         $page->assign('xorg_title','Polytechnique.org - Annuaire');
+         $page->setTitle('Polytechnique.org - Annuaire');
      }
  
      function handler_advanced(&$page, $action = null, $subaction = null)
                  '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),
 +                'networking_type' => array('field' => 'network_type', 'table' => 'profile_networking_enum',
 +                                           'text' => 'name', 'exact' => false),
                  'groupex' => array('field' => 'id', 'table' => 'groupex.asso',
                                     'text' => "(a.cat = 'GroupesX' OR a.cat = 'Institutions') AND pub = 'public' AND nom",
                                     'exact' => false),
                  'city' => array('table' => 'geoloc_city', 'text' => 'name', 'exact' => false)
              );
              if (!Env::has('page')) {
-                 $_SESSION['log']->log('search', 'adv=' . var_export($_GET, true));
+                 S::logger()->log('search', 'adv=' . var_export($_GET, true));
              }
              foreach ($textFields as $field=>&$query) {
                  if (!Env::v($field) && Env::v($field . 'Txt')) {
  
              require_once 'userset.inc.php';
              $view = new SearchSet(false, $action == 'geoloc' && substr($subaction, -3) == 'swf');
-             $view->addMod('minifiche', 'Minifiches', true);
+             $view->addMod('minifiche', 'Mini-fiches', true);
              $view->addMod('trombi', 'Trombinoscope', false, array('with_promo' => true));
              //$view->addMod('geoloc', 'Planisphère', false, array('with_annu' => 'search/adv'));
              $view->apply('search/adv', $page, $action, $subaction);
                  $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`)';
            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`';
@@@ -19,8 -19,6 +19,6 @@@
   *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                *
   ***************************************************************************/
  
- require_once("xorg.misc.inc.php");
  // {{{ Global variables used for the search Queries
  
  @$globals->search->result_fields = '
  // 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,';
 +        e.entreprise,
 +        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,";
 +        IF(e.pub='public', e.entreprise, '') 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  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\')';
 +    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\')
 +    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
@@@ -94,9 -90,10 +92,10 @@@ class ThrowErro
       */
      private static function defaultHandler($explain)
      {
-         global $page, $globals;
+         global $globals;
+         $page =& Platal::page();
          $page->changeTpl('search/index.tpl');
-         $page->assign('xorg_title','Polytechnique.org - Annuaire');
+         $page->setTitle('Polytechnique.org - Annuaire');
          $page->assign('baseurl', $globals->baseurl);
          $page->trigError($explain);
          $page->run();
@@@ -212,8 -209,6 +211,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);
      }
  
      // }}}
          $s = preg_replace('!\d+!', ' ', $s);
          $this->strings = preg_split("![^a-zA-Z%]+!",$s, -1, PREG_SPLIT_NO_EMPTY);
          if (count($this->strings) > 5) {
-             global $page;
-             $page->trigWarning("Tu as indiqué trop d'éléments dans ta recherche, seuls les 5 premiers seront pris en compte");
+             Platal::page()->trigWarning("Tu as indiqué trop d'éléments dans ta recherche, seuls les 5 premiers seront pris en compte");
              $this->strings = array_slice($this->strings, 0, 5);
          }
  
          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;
 +        }
      }
  
      // }}}
              $ip = ip_to_uint($this->ip);
              $where[] = "( ls.ip = $ip OR ls.forward_ip = $ip ) AND ls.suid = 0";
          }
 +        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);
      }
          if (!empty($this->ip)) {
              $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;
      }
      // }}}
@@@ -513,39 -489,6 +511,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;
diff --combined templates/core/vcard.tpl
@@@ -40,10 -40,8 +40,10 @@@ EMAIL;TYPE=internet:{$vcard.forlife}@{#
  {if $vcard.virtualalias}
  EMAIL;TYPE=internet:{$vcard.virtualalias}
  {/if}
 -{if $vcard.mobile}
 -TEL;TYPE=cell:{$vcard.mobile|vcard_enc}
 +{if $vcard.tels}
 +{foreach item=tel from=$vcard.tels}
 +{if $tel.tel_type eq 'mobile'}TEL;TYPE=cell{else}{if $tel.tel_type eq 'fax'}FAX{else}TEL{/if};TYPE=home{/if}:{$tel.tel|vcard_enc}
 +{/foreach}
  {/if}
  {if $vcard.adr_pro}
  {if $vcard.adr_pro[0].entreprise}
@@@ -55,30 -53,29 +55,30 @@@ TITLE:{$vcard.adr_pro[0].poste|vcard_en
  {if $vcard.adr_pro[0].fonction}
  ROLE:{$vcard.adr_pro[0].fonction|vcard_enc}
  {/if}
 -{if $vcard.adr_pro[0].tel}
 -TEL;TYPE=work:{$vcard.adr_pro[0].tel|vcard_enc}
 -{/if}
 -{if $vcard.adr_pro[0].fax}
 -FAX;TYPE=work:{$vcard.adr_pro[0].fax|vcard_enc}
 +{if $vcard.adr_pro[0].tels}
 +{foreach item=tel from=$vcard.adr_pro[0].tels}
 +{if $tel.tel_type eq 'mobile'}TEL;TYPE=cell,work{else}{if $tel.tel_type eq 'fax'}FAX{else}TEL{/if};TYPE=work{/if}:{$tel.tel|vcard_enc}
 +{/foreach}
  {/if}
  ADR;TYPE=work:{format_adr adr=$vcard.adr_pro[0]}
  {/if}
  {foreach item=adr from=$vcard.adr}
  ADR;TYPE=home{if $adr.courier},postal{/if}:{format_adr adr=$adr}
 +{if $adr.tels}
  {foreach item=tel from=$adr.tels}
 -{if $tel.tel}
 -{if $tel.tel_type neq 'Fax'}TEL{else}FAX{/if};TYPE=home:{$tel.tel}
 -{/if}
 +{if $tel.tel_type eq 'mobile'}TEL;TYPE=cell,home{else}{if $tel.tel_type eq 'fax'}FAX{else}TEL{/if};TYPE=home{/if}:{$tel.tel|vcard_enc}
  {/foreach}
 +{/if}
  {/foreach}
 -{if $vcard.web}
 -URL:{$vcard.web}
 +{foreach from=$vcard.networking item=nw}
 +{if $nw.filter eq 'web'}
 +URL:{$nw.address}
  {/if}
 +{/foreach}
  {if strlen(trim($vcard.freetext)) == 0}
  NOTE:(X{$vcard.promo})
  {else}
- NOTE:(X{$vcard.promo})\n{$vcard.freetext|vcard_enc}
+ NOTE:(X{$vcard.promo})\n{$vcard.freetext|miniwiki:'no_title':'text'|vcard_enc}
  {/if}
  {if $vcard.section}
  X-SECTION:{$vcard.section}
@@@ -27,7 -27,6 +27,7 @@@
    </p>
  {/if}
  {if $retour == $smarty.const.ERROR_INVALID_EMAIL}
 +  {assign var='error_email' value='1'}
    <p class="erreur">
    Erreur: l'email n'est pas valide.
    </p>
          </td>
        </tr>
        {/foreach}
 -      <tr class="{cycle values="pair,impair"}"><td colspan="4">
 -        <form action="emails/redirect" method="post">
 -        <div>
 -          &nbsp;<br />
 -          Ajouter une adresse email&nbsp;:
 -          <input type="text" size="35" maxlength="60" name="email" value="" />
 -          &nbsp;&nbsp;<input type="submit" value="ajouter" name="emailop" />
 +      <form action="emails/redirect" method="post">
 +        {cycle values="pair,impair" assign=class_combobox}
 +        {include file="include/emails.combobox.tpl" name="email" val=$email class=$class_combobox error=$error_email}
 +        <tr class=$class_combobox><td colspan="4"><div>
 +          <input type="submit" value="ajouter" name="emailop" />
            {xsrf_token_field}
 -        </div>
 -        </form>
 -      </td></tr>
 +        </div></td></tr>
 +      </form>
      </table>
      <script type="text/javascript">showRemove(); activeEnable();</script>
    </div>
  {/if}
  {if #globals.mailstorage.imap_active# or hasPerm('admin')}
  <p>
-   Polytechnique.org te propose de conserver les mails que tu reçois, pendant une durée limitée (environ 30 jours).
-   Grâce à ce service, tu disposes d'une sauvegarde de tes mails en secours, au cas où, par exemple, tu effacerais
-   un mail par erreur.<br />
+   Polytechnique.org te propose de conserver les emails que tu reçois, pendant une durée limitée (environ 30 jours).
+   Grâce à ce service, tu disposes d'une sauvegarde de tes emails en secours, au cas où, par exemple, tu effacerais
+   un email par erreur.<br />
    <strong>Attention :</strong> il ne s'agit que d'un service de secours, dont la disponibilité n'est pas garantie.
  </p>
  
    {$smarty.session.forlife}@{#globals.mail.domain#} (attention, cela demande de la concentration).
  </p>
  <p>
-   Si tu utilises le service POP de poly pour récupérer tes mails dans ton logiciel de courrier,
+   Si tu utilises le service POP de poly pour récupérer tes emails dans ton logiciel de courrier,
    l'équipe de Polytechnique.org te conseille de rediriger&nbsp;:
  </p>
  <ul>
      {if $smarty.session.auth ge AUTH_COOKIE}
      <div class="photo">
        <img src="photo/{if $c.inscrit}{$c.forlife}{else}{make_forlife nom=$c.nom prenom=$c.prenom promo=$c.promo}{/if}"
 -           alt="{$c.prenom} {$c.nom}" />
 +           alt="{$c.name_display}" />
      </div>
      {/if}
  
      <div class="nom">
        {if $c.sexe}&bull;{/if}
        {if !$c.dcd && ($c.inscrit || $smarty.session.auth eq AUTH_PUBLIC)}<a href="profile/{if $c.inscrit}{$c.forlife}{else}{make_forlife nom=$c.nom prenom=$c.prenom promo=$c.promo}{/if}" class="popup2">{/if}
 -      {if $c.nom_usage}{$c.nom_usage} {$c.prenom}<br />({$c.nom}){else}{$c.nom} {$c.prenom}{/if}
 +      <span {if $c.name_tooltip}class="hinted" title="{$c.name_tooltip}"{/if}>{$c.name_display}</span>
        {if !$c.dcd && ($c.inscrit || $smarty.session.auth eq AUTH_PUBLIC)}</a>{/if}
      </div>
  
        {if $c.iso3166}
        <img src='images/flags/{$c.iso3166}.gif' alt='{$c.nat}' height='11' title='{$c.nat}' />&nbsp;
        {/if}
-       (X {$c.promo}{if $c.app0text}, {applis_fmt type=$c.app0type text=$c.app0text url=$c.app0url}{*
-       *}{/if}{if $c.app1text}, {applis_fmt type=$c.app1type text=$c.app1text url=$c.app1url}{/if})
-       {if $c.dcd}décédé{if $c.sexe}e{/if} le {$c.deces|date_format}{/if}
-       {if $smarty.session.auth ge AUTH_COOKIE}
-       {if !$c.dcd && !$c.wasinscrit}
-       <a href="marketing/public/{$c.user_id}" class='popup'>clique ici si tu connais son adresse email !</a>
-       {/if}
-       {/if}
+       X {$c.promo}{if $c.app0text}, {applis_fmt type=$c.app0type text=$c.app0text url=$c.app0url}{*
+       *}{/if}{if $c.app1text}, {applis_fmt type=$c.app1type text=$c.app1text url=$c.app1url}{/if}{*
+       *}{if $c.dcd}, décédé{if $c.sexe}e{/if} le {$c.deces|date_format}{/if}
      </div>
    </div>
  
  
      {if hasPerm('admin')}
      <div>
-     {if !$c.wasinscrit && !$c.dcd}
-     <a href="marketing/private/{$c.user_id}">{*
-       *}{icon name=email title="marketter user"}</a>
-     {/if}
-     <a href="admin/user/{if $c.wasinscrit}{$c.forlife}{else}{$c.user_id}{/if}">{*
-     *}{icon name=wrench title="administrer user"}</a>
-     <a href="http://www.polytechniciens.com/?page=AX_FICHE_ANCIEN&amp;anc_id={$c.matricule_ax}">{*
-     *}{icon name=user_gray title="fiche AX"}</a>
+       [{if !$c.wasinscrit && !$c.dcd}
+       <a href="marketing/private/{$c.user_id}">{*
+         *}{icon name=email title="marketter user"}</a>
+       {/if}
+       <a href="admin/user/{if $c.wasinscrit}{$c.forlife}{else}{$c.user_id}{/if}">{*
+       *}{icon name=wrench title="administrer user"}</a>
+       <a href="http://www.polytechniciens.com/?page=AX_FICHE_ANCIEN&amp;anc_id={$c.matricule_ax}">{*
+       *}{icon name=user_gray title="fiche AX"}</a>]
      </div>
      {/if}
    </div>
    {/if}
  
    <div class="long">
-   {if $c.wasinscrit}
+   {if $c.wasinscrit || !$c.dcd}
      {if $c.web || $c.mobile || $c.countrytxt || $c.city || $c.region || $c.entreprise || $c.freetext || (!$c.dcd && !$c.actif )}
      <table cellspacing="0" cellpadding="0">
        {if $c.web}
        <tr>
-         <td class="lt">Page web:</td>
+         <td class="lt">Page web&nbsp;:</td>
          <td class="rt"><a href="{$c.web}">{$c.web}</a></td>
        </tr>
        {/if}
        {if $c.countrytxt || $c.city}
        <tr>
-         <td class="lt">Géographie:</td>
+         <td class="lt">Géographie&nbsp;:</td>
          <td class="rt">{$c.city}{if $c.city && $c.countrytxt}, {/if}{$c.countrytxt}</td>
        </tr>
        {/if}
        {if $c.mobile && !$c.dcd}
        <tr>
-         <td class="lt">Mobile:</td>
+         <td class="lt">Mobile&nbsp;:</td>
          <td class="rt">{$c.mobile}</td>
        </tr>
        {/if}
        {if $c.entreprise}
        <tr>
-         <td class="lt">Profession:</td>
+         <td class="lt">Profession&nbsp;:</td>
          <td class="rt">
            {$c.entreprise} {if $c.secteur}({$c.secteur}){/if}
            {if $c.fonction}<br />{$c.fonction}{/if}
        {/if}
        {if $c.freetext}
        <tr>
-         <td class="lt">Commentaire:</td>
+         <td class="lt">Commentaire&nbsp;:</td>
          <td class="rt">{$c.freetext|nl2br}</td>
        </tr>
        {/if}
-       {if !$c.dcd && !$c.actif && $c.wasinscrit && $smarty.session.auth ge AUTH_COOKIE}
+       {if !$c.dcd && (!$c.actif || !$c.wasinscrit) && $smarty.session.auth ge AUTH_COOKIE}
        <tr>
          <td class="smaller" colspan="2">
-           Ce camarade n'a plus d'adresse de redirection valide.
+           {if !$c.wasinscrit}
+           Ce{if $c.sexe}tte{/if} camarade n'est pas inscrit{if $c.sexe}e{/if}.
+           <a href="marketing/public/{$c.user_id}" class='popup'>Si tu connais son adresse email,
+           <strong>n'hésite pas à nous la transmettre !</a>
+           {elseif !$c.actif}
+           Ce{if $c.sexe}tte{/if} camarade n'a plus d'adresse de redirection valide.
            <a href="marketing/broken/{$c.forlife}">
-             Si tu en connais une, <strong>n'hésite pas à nous la transmettre</strong>
+             Si tu en connais une, <strong>n'hésite pas à nous la transmettre</strong>.
            </a>
+           {/if}
          </td>
        </tr>
        {/if}
  {**************************************************************************}
  
  <div class="contact-list" style="clear: both">
- {iterate from=$set item=p} 
+ {foreach from=$set item=p} 
    <div class="contact"> 
      <div class="nom"> 
 -      {$p.nom} {$p.prenom} 
 +      <span {if $p.name_tooltip}class="hinted" title="{$p.name_tooltip}"{/if}>{$p.name_display}</span>
      </div> 
      <div class="appli"> 
        X{$p.promo} 
      </div> 
      <div class="bits" style="width: 40%;"> 
        <span class='smaller'> 
-       <a href="profile/{$p.bestalias}" class="popup2"> 
+       <a href="profile/{$p.forlife}" class="popup2">
          {icon name=user_suit title="Voir sa fiche"}</a> - 
-         <a href="referent/{$p.bestalias}" class="popup2">Voir sa fiche référent</a> 
+         <a href="referent/{$p.forlife}" class="popup2">Voir sa fiche référent</a>
        </span> 
      </div> 
      <div class="long"> 
@@@ -45,7 -45,7 +45,7 @@@
       </table> 
      </div> 
    </div> 
- {/iterate}
+ {/foreach}
  </div>
  
  {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
    Aucun des camarades concernés n'a de photographie sur sa fiche
  </p>
  {else}
- <table cellpadding="8" cellspacing="2" style="width: 100%">
-   {iterate from=$set item=p}
-   {cycle values="1,2,3" assign="loop"}
-   {if $loop eq "1"}
+ <table cellpadding="0" cellspacing="2" style="width: 100%">
+   {section name=trombi loop=$set start=1}
+   {if $smarty.section.trombi.iteration % 3 == 1}
    <tr>
-   {/if}
-     <td class="center">
-       <a href="{$mainsiteurl}profile/{$p.forlife}" class="popup2">
-         <img src="photo/{$p.forlife}" width="110" alt=" [ PHOTO ] " />
+     <td class="center" style="vertical-align: middle">
+       <a href="{$mainsiteurl}profile/{$set[trombi.index_prev].forlife}" class="popup2">
+         <img src="photo/{$set[trombi.index_prev].forlife}" width="110" alt=" [ PHOTO ] " />
        </a>
        {if $trombi_with_admin && hasPerm('admin')}
-       <a href="{$mainsiteurl}admin/trombino/{$p.user_id}">{icon name=wrench title="[admin]"}</a>
+       <a href="{$mainsiteurl}admin/trombino/{$set[trombi.index_prev].user_id}">{icon name=wrench title="[admin]"}</a>
        {/if}
-       <br />
-       <a href="{$mainsiteurl}profile/{$p.forlife}" class="popup2">
-         <span {if $p.name_tooltip}class="hinted" title="{$p.name_tooltip}"{/if}>{$p.name_display}</span>{if $trombi_with_promo} ({$p.promo}){/if}
+     </td>
+     <td class="center" style="vertical-align: middle">
+       <a href="{$mainsiteurl}profile/{$set[trombi].forlife}" class="popup2">
+         <img src="photo/{$set[trombi].forlife}" width="110" alt=" [ PHOTO ] " />
        </a>
+       {if $trombi_with_admin && hasPerm('admin')}
+       <a href="{$mainsiteurl}admin/trombino/{$set[trombi].user_id}">{icon name=wrench title="[admin]"}</a>
+       {/if}
+     </td>
+     <td class="center" style="vertical-align: middle">
+     {if $set[trombi.index_next]}
+       <a href="{$mainsiteurl}profile/{$set[trombi.index_next].forlife}" class="popup2">
+         <img src="photo/{$set[trombi.index_next].forlife}" width="110" alt=" [ PHOTO ] " />
+       </a>
+       {if $trombi_with_admin && hasPerm('admin')}
+       <a href="{$mainsiteurl}admin/trombino/{$set[trombi.index_next].user_id}">{icon name=wrench title="[admin]"}</a>
+       {/if}
+     {/if}
      </td>
-   {if $loop eq "3"}
+   </tr>
+   <tr>
+     <td class="center" style="vertical-align: bottom; padding-bottom: 15px">
+       <a href="{$mainsiteurl}profile/{$set[trombi.index_prev].forlife}" class="popup2">
 -        {$set[trombi.index_prev].prenom} {$set[trombi.index_prev].nom}{if $trombi_with_promo} ({$set[trombi.index_prev].promo}){/if}
++        <span {if $set[trombi.index_prev].name_tooltip}class="hinted" title="{$set[trombi.index_prev].name_tooltip}"{/if}>{$set[trombi.index_prev].name_display}</span>{if $trombi_with_promo} ({$set[trombi.index_prev].promo}){/if}
+       </a>
+     </td>
+     <td class="center" style="vertical-align: bottom; padding-bottom: 15px">
+       <a href="{$mainsiteurl}profile/{$set[trombi].forlife}" class="popup2">
 -        {$set[trombi].prenom} {$set[trombi].nom}{if $trombi_with_promo} ({$set[trombi].promo}){/if}
++        <span {if $set[trombi].name_tooltip}class="hinted" title="{$set[trombi].name_tooltip}"{/if}>{$set[trombi].name_display}</span>{if $trombi_with_promo} ({$set[trombi].promo}){/if}
+       </a>
+     </td>
+     <td class="center" style="vertical-align: bottom; padding-bottom: 15px">
+     {if $set[trombi.index_next]}
+       <a href="{$mainsiteurl}profile/{$set[trombi.index_next].forlife}" class="popup2">
 -        {$set[trombi.index_next].prenom} {$set[trombi.index_next].nom}{if $trombi_with_promo} ({$set[trombi.index_next].promo}){/if}
++        <span {if $set[trombi.index_next].name_tooltip}class="hinted" title="{$set[trombi.index_next].name_tooltip}"{/if}>{$set[trombi.index_next].name_display}</span>{if $trombi_with_promo} ({$set[trombi.index_next].promo}){/if}
+       </a>
+     {/if}
+     </td>
+   </tr>
+   {elseif ($smarty.section.trombi.iteration % 3 == 0) && ($smarty.section.trombi.last)}
+   <tr>
+     <td class="center" style="vertical-align: middle; padding-bottom: 15px">
+       <a href="{$mainsiteurl}profile/{$set[trombi].forlife}" class="popup2">
+         <img src="photo/{$set[trombi].forlife}" width="110" alt=" [ PHOTO ] " />
+       </a>
+       {if $trombi_with_admin && hasPerm('admin')}
+       <a href="{$mainsiteurl}admin/trombino/{$set[trombi].user_id}">{icon name=wrench title="[admin]"}</a>
+       {/if}
+     </td>
+     <td></td><td></td>
+   </tr>
+   <tr style="margin-top: 0; padding-top: 0">
+     <td class="center" style="vertical-align: bottom">
+       <a href="{$mainsiteurl}profile/{$set[trombi].forlife}" class="popup2">
 -        {$set[trombi].prenom} {$set[trombi].nom}{if $trombi_with_promo} ({$set[trombi].promo}){/if}
++        <span {if $set[trombi].name_tooltip}class="hinted" title="{$set[trombi].name_tooltip}"{/if}>{$set[trombi].name_display}</span>{if $trombi_with_promo} ({$set[trombi].promo}){/if}
+       </a>
+     </td>
+     <td></td><td></td>
    </tr>
    {/if}
-   {/iterate}
-   {if $loop neq "3"}
-   {if $lopp eq "1"}
-   <td></td>
-   {/if}
-   <td></td></tr>
-   {/if}
+   {/section}
  </table>
  {/if}
  
@@@ -45,7 -45,7 +45,7 @@@ sa dernière relance date du {$relance|
  {/if}
  </p>
  
- <p>[<a href='{$path}/insrel'>le relancer</a>]</p>
+ <p>[<a href='{$path}/insrel?token={xsrf_token}'>le relancer</a>]</p>
  
  {/if}
  
      {iterate from=$addr item=a}
      <tr class="{cycle values='impair,pair'}">
        <td>{$a.email}</td>
 -      <td><a href="profile/{$a.alias}" class="popup2">{$a.alias}</a> {if $a.type eq user}(*){/if}</td>
 +      <td>
 +        {if $a.alias neq ''}<a href="profile/{$a.alias}" class="popup2">{$a.alias}</a>
 +        {if $a.type eq user}(*){/if}{else}Email connu de l'AX{/if}
 +      </td>
        <td>{$a.date|date_format|default:'-'}</td>
        <td>{$a.last|date_format|default:'-'}</td>
        <td class='center'>{$a.nb|default:"-"}</td>
        <td class='action'>
-         <a href='{$path}/del/{$a.email}'>del</a><br />
+         <a href='{$path}/del/{$a.email}?token={xsrf_token}'>del</a><br />
          <a href='{$path}/rel/{$a.email}'>relance</a>
        </td>
      </tr>
      {/iterate}
      <tr>
        <td></td>
-       <td colspan='5' class='smaller'>(*): mail perso</td>
+       <td colspan='5' class='smaller'>(*): email perso</td>
      </tr>
      <tr>
        <td>
  
  {if $rel_to}
  <form action="{$path}/relforce/{$email}" method="post">
+   {xsrf_token_field}
    <table class="bicol">
      <tr class="pair">
-       <th colspan="2">Edition dmail de relance</th>
+       <th colspan="2">Edition de l'email de relance</th>
      </tr>
      <tr class="pair">
        <td align="right"><strong>From:</strong></td>
@@@ -50,20 -50,6 +50,20 @@@ function chgMainWinLoc(strPage
        {if $x.gpxs_join}<div><em class="intitule">Groupe{if count($x.gpxs) > 1}s{/if} et institution{if count($x.gpxs) > 1}s{/if} X&nbsp;: </em>
        <span><br/>{$x.gpxs_join|smarty:nodefaults}</span></div>{/if}
      {/if}
 +    {if $x.networking}
 +      <h2>Sur le web...</h2>
 +      {foreach from=$x.networking item=network}
 +        <img style="width: auto; padding: 0" src="profile/networking/{$network.type}" alt="{$network.name}" title="{$network.name}"/>
 +        {if $network.filter == 'web'}
 +          <a href="{$network.address}">{$network.address}</a>
 +        {elseif $network.link != ''}
 +          <a href="{$network.link}">{$network.address}</a>
 +        {else}
 +          {$network.address}
 +        {/if}
 +        <br/>
 +      {/foreach}
 +    {/if}
      {if $x.freetext}
      <h2>Commentaires&nbsp;:</h2>
      <span>{$x.freetext|miniwiki|smarty:nodefaults}</span>
    <div id="fiche_identite" class="part">
      <div class="civilite">
        {if $x.sexe}&bull;{/if}
 -      {$x.prenom} {if $x.nom_usage eq ""}{$x.nom}{else}{$x.nom_usage} ({$x.nom}){/if}
 +      <span {if $x.name_tooltip neq ""}class="hinted" title="{$x.name_tooltip}"{/if}>{$x.name_display}</span>
        {if $logged}
        {if $x.nickname} (alias {$x.nickname}){/if}
        {/if}
 -      {if $x.web}&nbsp;<a href="{$x.web}">{icon name="world_go" title="Site Web"}</a>{/if}
        {if $logged}
        &nbsp;{if !$x.dcd}<a href="vcard/{$x.forlife}.vcf">{*
          *}{icon name=vcard title="Afficher la carte de visite"}</a>{/if}
        le {$x.date|date_format}
      </div>
      {/if}
 -    {if $logged || $x.mobile}
 +    {if $logged || $x.tels}
      <div class="contact">
        {if $logged}
        <div class='email'>
          {if $x.dcd}
          Décédé{if $x.sexe}e{/if} le {$x.deces|date_format}
          {elseif !$x.actif}
-         Ce camarade n'a plus d'adresse de redirection valide,<br />
+         Ce{if $c.sexe}tte{/if} camarade n'a plus d'adresse de redirection valide,<br />
          <a href="marketing/broken/{$x.forlife}" class="popup">clique ici si tu connais son adresse email !</a>
          {elseif !$x.inscrit}
          Cette personne n'est pas inscrite à Polytechnique.org,<br />
          {/if}
        </div>
        {/if}
 -      {if $x.mobile}
 -      <div class="mob">
 -        <em class="intitule">Mobile&nbsp;: </em>{$x.mobile}
 -      </div>
 +      {if $x.tels}
 +        {display_phones tels=$x.tels}
        {/if}
        <div class='spacer'></div>
      </div>
  
                return false;
              });
+         }).parent().find('.autocomplete').change(function() {
+           // If we change the value in the type="text" field, then the value in the 'integer id' field must not be used,
+           // to ensure that, we unset it
+           $(this).parent().find('.autocompleteTarget').val('');
          });
      });
  -->
@@@ -404,29 -408,6 +408,29 @@@ checked="checked"{/if}/>Chercher unique
        <td>Commentaire contient</td>
        <td><input type="text" name="free" size="32" value="{$smarty.request.free}" /></td>
      </tr>
 +    <tr>
 +      <td>Numéro de téléphone</td>
 +      <td><input type="text" name="phone_number" size="32" value="{$smarty.request.phone_number}"/></td>
 +    </tr>
 +    <tr>
 +      <td style="vertical-align: middle">
 +        <span>Networking et sites webs</span>
 +      </td>
 +      <td>
 +        <table>
 +          <tr>
 +            <td style="padding-left: 0px;">
 +              <input type="text" name="networking_address" size="32" value="{$smarty.request.networking_address}" />
 +            </td>
 +            <td>
 +              <input type="text" name="networking_typeTxt" class="autocomplete" size="10" value="{$smarty.request.networking_typeTxt}" />
 +              <input name="networking_type" class="autocompleteTarget" type="hidden" value="{$smarty.request.networking_type}"/>
 +              <a href="networking_type" class="autocompleteToSelect">{icon name="table" title="Tous les types d'adresse"}</a>
 +            </td>
 +          </tr>
 +        </table>
 +      </td>
 +    </tr>
          {if $smarty.session.auth ge AUTH_COOKIE}
      <tr>
        <td colspan="2">