OSDN Git Service

MERGE: リビジョン1821。Member::create()においてクエリ文を生成する際のバグを修正
[nucleus-jp/nucleus-next.git] / nucleus / libs / MEMBER.php
index 73689fc..f909f3d 100644 (file)
-<?php
-
-/*
- * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
- * Copyright (C) 2002-2009 The Nucleus Group
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * (see nucleus/documentation/index.html#license for more info)
- */
-/**
- * A class representing site members
- *
- * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2009 The Nucleus Group
- * @version $Id: MEMBER.php 1616 2012-01-08 09:48:15Z sakamocchi $
- */
-class MEMBER {
-       
-       // 1 when authenticated, 0 when not
-       public $loggedin = 0;
-       public $password;               // not the actual password, but rather a MD5 hash
-       private $algorism = 'md5';
-       
-       public $cookiekey;              // value that should also be in the client cookie to allow authentication
-       
-       // member info
-       public $id = -1;
-       public $realname;
-       public $displayname;
-       public $email;
-       public $url;
-       public $admin = 0;                      // (either 0 or 1)
-       public $canlogin = 0;           // (either 0 or 1)
-       public $notes;
-       public $autosave = 1;           // if the member use the autosave draft function
-       private $locale = '';
-       
-       /* NOTE: $locale value obsoleted $language value since version 4.0 */
-       public $language = '';
-       
-       /**
-        * MEMBER::__construct()
-        * Constructor for a member object
-        * 
-        * @param       Void
-        * @return      Void
-        * 
-        */
-       public function __construct()
-       {
-               /* secure cookie key settings (either 'none', 0, 8, 16, 24, or 32) */
-               if ( !array_key_exists('secureCookieKey', $CONF) )
-               {
-                       $CONF['secureCookieKey'] = 24;
-               }
-               
-               switch( $CONF['secureCookieKey'] )
-               {
-                       case 8:
-                               $CONF['secureCookieKeyIP'] = preg_replace('/\.[0-9]+\.[0-9]+\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
-                               break;
-                       case 16:
-                               $CONF['secureCookieKeyIP'] = preg_replace('/\.[0-9]+\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
-                               break;
-                       case 24:
-                               $CONF['secureCookieKeyIP'] = preg_replace('/\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
-                               break;
-                       case 32:
-                               $CONF['secureCookieKeyIP'] = serverVar('REMOTE_ADDR');
-                               break;
-                       default:
-                               $CONF['secureCookieKeyIP'] = '';
-               }
-               
-               return;
-       }
-       
-       /**
-        * MEMBER::createFromName()
-        * Create a member object for a given displayname
-        *
-        * @static      
-        * @param       String  $displayname    login name
-        * @return      Object  member object
-        * 
-        */
-       public static function &createFromName($displayname)
-       {
-               $mem = new MEMBER();
-               $mem->readFromName($displayname);
-               return $mem;
-       }
-
-       /**
-        * MEMBER::createFromID()
-        * Create a member object for a given ID
-        *
-        * @static      
-        * @param       Integer $id     id for member
-        */
-       public static function &createFromID($id)
-       {
-               $mem = new MEMBER();
-               $mem->readFromID($id);
-               return $mem;
-       }
-       
-       /**
-        * MEMBER::readFromName()
-        * Read member table in database
-        * 
-        * @param       String  $displayname    login name
-        * @return      Object  SQL resource
-        * 
-        */
-       public function readFromName($displayname)
-       {
-               return $this->read("mname='".sql_real_escape_string($displayname)."'");
-       }
-       
-       /**
-        * MEMBER::readFromID()
-        * Read member table in database
-        * 
-        * @param       Integer $id     id for member
-        * @return      Object  SQL resource
-        * 
-        */
-       public function readFromID($id)
-       {
-               return $this->read("mnumber=" . intval($id));
-       }
-       
-       /**
-        * MEMBER::hash()
-        * hash the target string
-        * 
-        * @param       String  $string target string
-        * @return      Void    hashed string
-        */
-       public function hash($string)
-       {
-               switch ( $this->algorism )
-               {
-                       case 'md5':
-                       default:
-                               $string = md5($string);
-               }
-               
-               return $string;
-       }
-       
-       /**
-        * MEMBER::login()
-        * Tries to login as a given user.
-        * Returns true when succeeded, returns false when failed
-        * 3.40 adds CustomLogin event
-        * 
-        * @param       String  $login  login name for member
-        * @param       String  $password       password for member
-        * @param       Integer $shared whether the user agent is shared or not
-        * 
-        */
-       public function login($login, $password, $shared=1)
-       {
-               global $CONF, $errormessage, $manager;
-               
-               /* TODO: validation for $login, $password, $shared */
-               if ( $login == '' || $password == '' )
-               {
-                       return 0;
-               }
-               /* limiting the length of password to avoid hash collision */
-               $password=i18n::substr($password, 0, 40);
-               
-               $success = 0;
-               $allowlocal = 1;
-               $manager->notify('CustomLogin', array('login' => &$login, 'password'=>&$password, 'success'=>&$success, 'allowlocal'=>&$allowlocal));
-               
-               $this->loggedin = 0;
-               if ( $success )
-               {
-                       $this->loggedin = ( $this->readFromName($login) );
-               }
-               elseif ( $allowlocal )
-               {
-                       $this->loggedin = ( $this->readFromName($login) && $this->checkPassword($password) );
-               }
-               
-               /* login failed */
-               if ( !$this->loggedin )
-               {
-                       $trimlogin = trim($login);
-                       if ( empty($trimlogin) )
-                       {
-                               $errormessage = "Please enter a username.";
-                       }
-                       else 
-                       {
-                               $errormessage = 'Login failed for ' . $login;
-                       }
-                       $manager->notify('LoginFailed', array('username' => $login) );
-                       ACTIONLOG::add(INFO, $errormessage);
-               }
-               /* login success */
-               else
-               {
-                       $this->newCookieKey();
-                       $this->setCookies($shared);
-                       
-                       if ( $CONF['secureCookieKey'] !== 'none' )
-                       {
-                               /* secure cookie key */
-                               $this->setCookieKey($this->hash($this->getCookieKey().$CONF['secureCookieKeyIP']));
-                               $this->write();
-                       }
-                       
-                       $errormessage = '';
-                       $manager->notify('LoginSuccess', array('member' => &$member, 'username' => $login) );
-                       ACTIONLOG::add(INFO, "Login successful for $login (sharedpc=$shared)");
-               }
-               
-               return $this->loggedin;
-       }
-       
-       /**
-        * MEMBER::cookielogin()
-        * Login using cookie key
-        * 
-        * @param       String  $login  not used
-        * @param       String  $cookiekey      not used
-        * @return      Boolean login or not
-        */
-       public function cookielogin($login='', $cookiekey='')
-       {
-               global $CONF, $manager;
-               
-               if ( !headers_sent() && cookieVar("{$CONF['CookiePrefix']}user") )
-               {
-                       /* Cookie Authentication */
-                       $ck = cookieVar("{$CONF['CookiePrefix']}loginkey");
-                       
-                       /* TODO: validation for each cookie values */
-                       
-                       /* limiting the length of password to avoid hash collision */
-                       $ck = i18n::substr($ck,0,32);
-                       if ( $CONF['secureCookieKey']!=='none' )
-                       {
-                               $ck = $this->hash("{$ck}{$CONF['secureCookieKeyIP']}");
-                       }
-                       $this->loggedin = ( $this->readFromName(cookieVar("{$CONF['CookiePrefix']}user")) && $this->checkCookieKey($ck) );
-                       unset($ck);
-                       
-                       /* renew cookies when not on a shared computer */
-                       if ( $res && (cookieVar($CONF['CookiePrefix'] . 'sharedpc') != 1) )
-                       {
-                               $member->setCookieKey(cookieVar("{$CONF['CookiePrefix']}loginkey"));
-                               $member->setCookies();
-                       }
-               }
-               return $this->loggedin;
-       }
-       
-       /**
-        * MEMBER::logout()
-        * logout and expire cookie
-        * 
-        * @param       Void
-        * @return      Void
-        */
-       public function logout()
-       {
-               global $CONF, $manager;
-               
-               if ( !headers_sent() && cookieVar("{$CONF['CookiePrefix']}user") )
-               {
-                       /* remove cookies on logout */
-                       setcookie("{$CONF['CookiePrefix']}user", '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
-                       setcookie("{$CONF['CookiePrefix']}loginkey", '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
-                       $manager->notify('Logout', array('username' => cookieVar("{$CONF['CookiePrefix']}user") ) );
-               }
-               
-               $this->loggedin = 0;
-               return;
-       }
-       
-       /**
-        * MEMBER::isLoggedIn()
-        * return member is loggedin or not
-        * 
-        * @param       Void
-        * @return      Void
-        */
-       public function isLoggedIn()
-       {
-               return $this->loggedin;
-       }
-       
-       /**
-        * MEMBER:read()
-        * Read member information from the database 
-        * 
-        * @param       String  $where  where statement
-        * @return      Resource        SQL resource
-        * 
-        */
-       public function read($where)
-       {
-               // read info
-               $query =  'SELECT * FROM '.sql_table('member') . ' WHERE ' . $where;
-               
-               $res = sql_query($query);
-               $obj = sql_fetch_object($res);
-               
-               $this->setRealName($obj->mrealname);
-               $this->setEmail($obj->memail);
-               $this->password = $obj->mpassword;
-               $this->setCookieKey($obj->mcookiekey);
-               $this->setURL($obj->murl);
-               $this->setDisplayName($obj->mname);
-               $this->setAdmin($obj->madmin);
-               $this->id = $obj->mnumber;
-               $this->setCanLogin($obj->mcanlogin);
-               $this->setNotes($obj->mnotes);
-               $this->setLocale($obj->mlocale);
-               $this->setAutosave($obj->mautosave);
-               
-               return sql_num_rows($res);
-       }
-       
-       /**
-        * MEMBER::isBlogAdmin()
-        * Returns true if member is an admin for the given blog
-        * (returns false if not a team member)
-        * 
-        * @param       Integer $blogid weblog id
-        * @return      Integer weblog admin or not
-        * 
-        */
-       public function isBlogAdmin($blogid)
-       {
-               $query = 'SELECT tadmin FROM '.sql_table('team').' WHERE'
-                          . ' tblog=' . intval($blogid)
-                          . ' and tmember='. $this->getID();
-               $res = sql_query($query);
-               if ( sql_num_rows($res) == 0 )
-                       return 0;
-               else
-                       return ( sql_result($res,0,0) == 1 );
-       }
-       
-       public function blogAdminRights($blogid)
-       {
-               return ($this->isAdmin() || $this->isBlogAdmin($blogid));
-       }
-       
-       public function teamRights($blogid)
-       {
-               return ($this->isAdmin() || $this->isTeamMember($blogid));
-       }
-
-       /*
-        * Returns true if this member is a team member of the given blog
-        */
-       function isTeamMember($blogid)
-       {
-               $query = 'SELECT * FROM '.sql_table('team').' WHERE'
-                          . ' tblog=' . intval($blogid)
-                          . ' and tmember='. $this->getID();
-               $res = sql_query($query);
-               return (sql_num_rows($res) != 0);
-       }
-
-       function canAddItem($catid)
-       {
-               global $manager;
-               
-               // if this is a 'newcat' style newcat
-               // no blog admin of destination blog -> NOK
-               // blog admin of destination blog -> OK
-               if ( strstr($catid,'newcat') )
-               {
-                       // get blogid
-                       list($blogid) = sscanf($catid,"newcat-%d");
-                       return $this->blogAdminRights($blogid);
-               }
-               
-               // category does not exist -> NOK
-               if ( !$manager->existsCategory($catid) )
-               {
-                       return 0;
-               }
-               
-               $blogid = getBlogIDFromCatID($catid);
-               
-               // no team rights for blog -> NOK
-               if (!$this->teamRights($blogid))
-               {
-                       return 0;
-               }
-               
-               // all other cases: OK
-               return 1;
-       }
-       
-       /*
-        * Returns true if this member can edit/delete a commentitem. This can be in the
-        * following cases:
-        *        - member is a super-admin
-        *   - member is the author of the comment
-        *   - member is admin of the blog associated with the comment
-        *   - member is author of the item associated with the comment
-        */
-       public function canAlterComment($commentid)
-       {
-               if ( $this->isAdmin() )
-               {
-                       return 1;
-               }
-       
-               $query =  'SELECT citem as itemid, iblog as blogid, cmember as cauthor, iauthor'
-                          . ' FROM '.sql_table('comment') .', '.sql_table('item').', '.sql_table('blog')
-                          . ' WHERE citem=inumber and iblog=bnumber and cnumber=' . intval($commentid);
-               $res = sql_query($query);
-               $obj = sql_fetch_object($res);
-       
-               return ($obj->cauthor == $this->getID()) or $this->isBlogAdmin($obj->blogid) or ($obj->iauthor == $this->getID());
-       }
-       
-       /*
-        * Returns true if this member can edit/delete an item. This is true in the following
-        * cases: - member is a super-admin
-        *             - member is the author of the item
-        *        - member is admin of the the associated blog
-        */
-       public function canAlterItem($itemid)
-       {
-               if ($this->isAdmin()) return 1;
-
-               $query =  'SELECT iblog, iauthor FROM '.sql_table('item').' WHERE inumber=' . intval($itemid);
-               $res = sql_query($query);
-               $obj = sql_fetch_object($res);
-               return ($obj->iauthor == $this->getID()) or $this->isBlogAdmin($obj->iblog);
-       }
-
-       /*
-        * Return true if member can be deleted. This means that there are no items
-        * posted by the member left
-        */
-       public function canBeDeleted()
-       {
-               $res = sql_query('SELECT * FROM '.sql_table('item').' WHERE iauthor=' . $this->getID());
-               return (sql_num_rows($res) == 0);
-       }
-
-       /*
-        * returns true if this member can move/update an item to a given category,
-        * false if not (see comments fot the tests that are executed)
-        *
-        * @param itemid
-        * @param newcat (can also be of form 'newcat-x' with x=blogid)
-        */
-       public function canUpdateItem($itemid, $newcat)
-       {
-               global $manager;
-
-               // item does not exists -> NOK
-               if ( !$manager->existsItem($itemid,1,1) )
-               {
-                       return 0;
-               }
-               
-               // cannot alter item -> NOK
-               if (!$this->canAlterItem($itemid))
-               {
-                       return 0;
-               }
-               
-               // if this is a 'newcat' style newcat
-               // no blog admin of destination blog -> NOK
-               // blog admin of destination blog -> OK
-               if (strstr($newcat,'newcat'))
-               {
-                       // get blogid
-                       list($blogid) = sscanf($newcat,'newcat-%d');
-                       return $this->blogAdminRights($blogid);
-               }
-               
-               // category does not exist -> NOK
-               if (!$manager->existsCategory($newcat))
-               {
-                       return 0;
-               }
-               
-               // get item
-               $item =& $manager->getItem($itemid,1,1);
-               
-               // old catid = new catid -> OK
-               if ($item['catid'] == $newcat)
-               {
-                       return 1;
-               }
-               
-               // not a valid category -> NOK
-               $validCat = quickQuery('SELECT COUNT(*) AS result FROM '.sql_table('category').' WHERE catid='.intval($newcat));
-               if ( !$validCat )
-               {
-                       return 0;
-               }
-               
-               // get destination blog
-               $source_blogid = getBlogIDFromItemID($itemid);
-               $dest_blogid = getBlogIDFromCatID($newcat);
-               
-               // not a team member of destination blog -> NOK
-               if ( !$this->teamRights($dest_blogid) )
-               {
-                       return 0;
-               }
-               
-               // if member is author of item -> OK
-               if ( $item['authorid'] == $this->getID() )
-               {
-                       return 1;
-               }
-               
-               // if member has admin rights on both blogs: OK
-               if ( ($this->blogAdminRights($dest_blogid)) && ($this->blogAdminRights($source_blogid)) )
-               {
-                       return 1;
-               }
-               
-               // all other cases: NOK
-               return 0;
-       }
-
-       /**
-         * Sets the cookies for the member
-         *
-         * @param shared
-         *             set this to 1 when using a shared computer. Cookies will expire
-         *             at the end of the session in this case.
-         */
-       public function setCookies($shared = 0)
-       {
-               global $CONF;
-               
-               if ( $CONF['SessionCookie'] || $shared )
-               {
-                       $lifetime = 0;
-               }
-               else
-               {
-                       $lifetime = time()+2592000;
-               }
-               
-               setcookie($CONF['CookiePrefix'] .'user',$this->getDisplayName(),$lifetime,$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);
-               setcookie($CONF['CookiePrefix'] .'loginkey', $this->getCookieKey(),$lifetime,$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);
-               
-               // make sure cookies on shared pcs don't get renewed
-               if ( $shared )
-               {
-                       setcookie($CONF['CookiePrefix'] .'sharedpc', '1',$lifetime,$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);
-               }
-               return;
-       }
-       
-       /**
-        * MEMBER::sendActivationLink()
-        * Send activation mail
-        * 
-        * @param       String  $type   activation type
-        * @param       String  $extra  extra info
-        * @return      Void
-        */
-       public function sendActivationLink($type, $extra='')
-       {
-               global $CONF;
-               
-               if ( !isset($CONF['ActivationDays']) )
-               {
-                       $CONF['ActivationDays'] = 2;
-               }
-               
-               // generate key and URL
-               $key = $this->generateActivationEntry($type, $extra);
-               $url = $CONF['AdminURL'] . 'index.php?action=activate&key=' . $key;
-               
-               // choose text to use in mail
-               switch ( $type )
-               {
-                       case 'register':
-                               $message = _ACTIVATE_REGISTER_MAIL;
-                               $subject = _ACTIVATE_REGISTER_MAILTITLE;
-                               break;
-                       case 'forgot':
-                               $message = _ACTIVATE_FORGOT_MAIL;
-                               $subject = _ACTIVATE_FORGOT_MAILTITLE;
-                               break;
-                       case 'addresschange':
-                               $message = _ACTIVATE_CHANGE_MAIL;
-                               $subject = _ACTIVATE_CHANGE_MAILTITLE;
-                               break;
-                       default;
-               }
-               
-               // fill out variables in text
-               $aVars = array(
-                       'siteName' => $CONF['SiteName'],
-                       'siteUrl' => $CONF['IndexURL'],
-                       'memberName' => $this->getDisplayName(),
-                       'activationUrl' => $url,
-                       'activationDays' => $CONF['ActivationDays']
-               );
-               
-               $message = TEMPLATE::fill($message, $aVars);
-               $subject = TEMPLATE::fill($subject, $aVars);
-               
-               // send mail
-               NOTIFICATION::mail($this->getEmail(), $subject ,$message, $CONF['AdminEmail'], i18n::get_current_charset());
-               
-               ACTIONLOG::add(INFO, _ACTIONLOG_ACTIVATIONLINK . ' (' . $this->getDisplayName() . ' / type: ' . $type . ')');
-               return;
-       }
-       
-       /*
-        * Returns an array of all blogids for which member has admin rights
-        */
-       public function getAdminBlogs()
-       {
-               $blogs = array();
-               
-               if ($this->isAdmin())
-               {
-                       $query = 'SELECT bnumber as blogid from '.sql_table('blog');
-               }
-               else
-               {
-                       $query = 'SELECT tblog as blogid from '.sql_table('team').' where tadmin=1 and tmember=' . $this->getID();
-               }
-               
-               $res = sql_query($query);
-               if ( sql_num_rows($res) > 0 )
-               {
-                       while ( $obj = sql_fetch_object($res) )
-                       {
-                               array_push($blogs, $obj->blogid);
-                       }
-               }
-               return $blogs;
-       }
-       
-       /*
-        * Returns an array of all blogids for which member has team rights
-        */
-       public function getTeamBlogs($incAdmin = 1)
-       {
-               $incAdmin = intval($incAdmin);
-               $blogs = array();
-               
-               if ( $this->isAdmin() && $incAdmin )
-               {
-                       $query = 'SELECT bnumber as blogid from '.sql_table('blog');
-               }
-               else
-               {
-                       $query = 'SELECT tblog as blogid from '.sql_table('team').' where tmember=' . $this->getID();
-               }
-               
-               $res = sql_query($query);
-               if ( sql_num_rows($res) > 0 )
-               {
-                       while ( $obj = sql_fetch_object($res) )
-                       {
-                               array_push($blogs, $obj->blogid);
-                       }
-               }
-               return $blogs;
-       }
-       
-       /**
-        * MEMBER::getNotifyFromMailAddress()
-        * 
-        * Returns an email address from which notification of commenting/karma voting can
-        * be sent. A suggestion can be given for when the member is not logged in
-        * 
-        * @param       String  $suggest        
-        * @return      String  mail address or suggestion
-        */
-       public function getNotifyFromMailAddress($suggest = "")
-       {
-               global $CONF;
-               if ( $this->isLoggedIn() )
-               {
-                       return $this->getDisplayName() . " <" . $this->getEmail() . ">";
-               }
-               else if ( NOTIFICATION::address_validation($suggest) )
-               {
-                       return $suggest;
-               }
-               else
-               {
-                       return $CONF['AdminEmail'];
-               }
-       }
-       
-       /*
-        * Write data to database
-        */
-       function write()
-       {
-               $query =  'UPDATE '.sql_table('member')
-                          . " SET mname='" . sql_real_escape_string($this->getDisplayName()) . "',"
-                          . "     mrealname='". sql_real_escape_string($this->getRealName()) . "',"
-                          . "     mpassword='". sql_real_escape_string($this->getPassword()) . "',"
-                          . "     mcookiekey='". sql_real_escape_string($this->getCookieKey()) . "',"
-                          . "     murl='" . sql_real_escape_string($this->getURL()) . "',"
-                          . "     memail='" . sql_real_escape_string($this->getEmail()) . "',"
-                          . "     madmin=" . $this->isAdmin() . ","
-                          . "     mnotes='" . sql_real_escape_string($this->getNotes()) . "',"
-                          . "     mcanlogin=" . $this->canLogin() . ","
-                          . "     mlocale='" . sql_real_escape_string($this->getLocale()) . "',"
-                          . "     mautosave=" . intval($this->getAutosave()) . ""                         
-                          . " WHERE mnumber=" . $this->getID();
-               sql_query($query);
-               return;
-       }
-       
-       public function checkCookieKey($key)
-       {
-               return ( ($key != '') && ( $key == $this->getCookieKey() ) );
-       }
-       
-       public function checkPassword($pw)
-       {
-               return ($this->hash($pw) == $this->getPassword());
-       }
-       
-       public function getRealName()
-       {
-               return $this->realname;
-       }
-
-       public function setRealName($name)
-       {
-               $this->realname = $name;
-       }
-
-       public function getEmail()
-       {
-               return $this->email;
-       }
-
-       public function setEmail($email)
-       {
-               $this->email = $email;
-       }
-
-       public function getPassword()
-       {
-               return $this->password;
-       }
-
-       public function setPassword($pwd)
-       {
-               $this->password = $this->hash($pwd);
-       }
-
-       public function getCookieKey()
-       {
-               return $this->cookiekey;
-       }
-       
-       /*
-        * Generate new cookiekey, save it, and return it
-        */
-       public function newCookieKey()
-       {
-               mt_srand( (double) microtime() * 1000000);
-               $this->cookiekey = $this->hash(uniqid(mt_rand()));
-               $this->write();
-               return $this->cookiekey;
-       }
-       
-       public function setCookieKey($val)
-       {
-               $this->cookiekey = $val;
-       }
-       
-       public function getURL()
-       {
-               return $this->url;
-       }
-       
-       public function setURL($site)
-       {
-               $this->url = $site;
-       }
-       
-       /*
-        * FIXME: $this->locale is always correct or not?
-        * NOTE: Deprecated, this will be obsoleted soon.
-        */
-       public function getLanguage()
-       {
-               if ( ($language = i18n::convert_locale_to_old_language_file_name($this->locale)) === FALSE )
-               {
-                       $language = '';
-               }
-               return $language;
-       }
-       
-       public function getLocale()
-       {
-               return $this->locale;
-       }
-       
-       /*
-        * FIXME: $locale value should obsolete $language value near future
-        */
-       public function setLocale($locale)
-       {
-               if ( !!preg_match('#^(.+)_(.+)_(.+)$#', $locale)
-                && ($locale = i18n::convert_old_language_file_name_to_locale($locale)) === FALSE )
-               {
-                       $locale = '';
-               }
-               $this->locale = $locale;
-               return;
-       }
-       
-       public function setDisplayName($nick)
-       {
-               $this->displayname = $nick;
-       }
-       
-       public function getDisplayName()
-       {
-               return $this->displayname;
-       }
-       
-       public function isAdmin()
-       {
-               return $this->admin;
-       }
-       
-       public function setAdmin($val)
-       {
-               $this->admin = $val;
-       }
-       
-       public function canLogin()
-       {
-               return $this->canlogin;
-       }
-       
-       public function setCanLogin($val)
-       {
-               $this->canlogin = $val;
-       }
-       
-       public function getNotes()
-       {
-               return $this->notes;
-       }
-       
-       public function setNotes($val)
-       {
-               $this->notes = $val;
-       }
-       
-       public function getAutosave()
-       {
-               return $this->autosave;
-       }
-       
-       public function setAutosave($val)
-       {
-               $this->autosave = $val;
-       }
-       
-       public function getID()
-       {
-               return $this->id;
-       }
-       
-       /*
-        * Returns true if there is a member with the given login name
-        * 
-        * @static
-        */
-       public static function exists($name)
-       {
-               $r = sql_query('select * FROM '.sql_table('member')." WHERE mname='".sql_real_escape_string($name)."'");
-               return ( sql_num_rows($r) != 0 );
-       }
-       
-       /*
-        * Returns true if there is a member with the given ID
-        *
-        * @static
-        */
-       public static function existsID($id)
-       {
-               $r = sql_query('select * FROM '.sql_table('member')." WHERE mnumber='".intval($id)."'");
-               return (sql_num_rows($r) != 0);
-       }
-       
-       /*
-        *  Checks if a username is protected. 
-        *  If so, it can not be used on anonymous comments
-        */
-       function isNameProtected($name)
-       {
-               // extract name
-               $name = strip_tags($name);
-               $name = trim($name);
-               return MEMBER::exists($name);
-       }
-       
-       /**
-        * MEMBER::create()
-        * 
-        * Adds a new member
-        * 
-        * @static
-        * @param       String  $name
-        * @param       String  $realname
-        * @param       String  $password
-        * @param       String  $email
-        * @param       String  $url
-        * @param       String  $admin
-        * @param       String  $canlogin
-        * @param       String  $notes
-        * @return      String  1 if success, others if fail
-        */
-       public static function create($name, $realname, $password, $email, $url, $admin, $canlogin, $notes)
-       {
-               if ( !NOTIFICATION::address_validation($email) )
-               {
-                       return _ERROR_BADMAILADDRESS;
-               }
-               
-               if ( !isValidDisplayName($name) )
-               {
-                       return _ERROR_BADNAME;
-               }
-               
-               if ( MEMBER::exists($name) )
-               {
-                       return _ERROR_NICKNAMEINUSE;
-               }
-               
-               if ( !$realname )
-               {
-                       return _ERROR_REALNAMEMISSING;
-               }
-               
-               if ( !$password )
-               {
-                       return _ERROR_PASSWORDMISSING;
-               }
-               
-               /*
-                *  begin if: sometimes user didn't prefix the URL with http:// or https://,
-                *  this cause a malformed URL. Let's fix it.
-                */
-               
-               if ( !preg_match('#^https?://#', $url) )
-               {
-                       $url = 'http://' . $url;
-               }
-               
-               $name = sql_real_escape_string($name);
-               $realname = sql_real_escape_string($realname);
-               $password = sql_real_escape_string($this->hash($password));
-               $email = sql_real_escape_string($email);
-               $url = sql_real_escape_string($url);
-               $admin = intval($admin);
-               $canlogin = intval($canlogin);
-               $notes = sql_real_escape_string($notes);
-               
-               $query = 'INSERT INTO '.sql_table('member')." (MNAME,MREALNAME,MPASSWORD,MEMAIL,MURL, MADMIN, MCANLOGIN, MNOTES) "
-                          . "VALUES ('$name','$realname','$password','$email','$url',$admin, $canlogin, '$notes')";
-               sql_query($query);
-               
-               ACTIONLOG::add(INFO, _ACTIONLOG_NEWMEMBER . ' ' . $name);
-               
-               return 1;
-       }
-       
-       /*
-        * Returns activation info for a certain key (an object with properties vkey, vmember, ...)
-        * (static)
-        *
-        * @author karma
-        */
-       public static function getActivationInfo($key)
-       {
-               $query = 'SELECT * FROM ' . sql_table('activation') . ' WHERE vkey=\'' . sql_real_escape_string($key). '\'';
-               $res = sql_query($query);
-               
-               if ( !$res || (sql_num_rows($res) == 0) )
-               {
-                       return 0;
-               }
-               else
-               {
-                       return sql_fetch_object($res);
-               }
-       }
-       
-       /*
-        * Creates an account activation key
-        *
-        * @param $type one of the following values (determines what to do when activation expires)
-        *                'register' (new member registration)
-        *                'forgot' (forgotton password)
-        *                'addresschange' (member address has changed)
-        * @param $extra extra info (needed when validation link expires)
-        *                                addresschange -> old email address
-        * @author dekarma
-        */
-       public function generateActivationEntry($type, $extra = '')
-       {
-               // clean up old entries
-               $this->cleanupActivationTable();
-               
-               // kill any existing entries for the current member (delete is ok)
-               // (only one outstanding activation key can be present for a member)
-               sql_query('DELETE FROM ' . sql_table('activation') . ' WHERE vmember=' . intval($this->getID()));
-               
-               // indicates if the member can log in while the link is active
-               $canLoginWhileActive = false;
-               switch ( $type )
-               {
-                       case 'forgot':
-                               $canLoginWhileActive = true;
-                               break;
-                       case 'register':
-                               break;
-                       case 'addresschange':
-                               $extra = $extra . '/' . ( $this->canLogin() ? '1' : '0' );
-                               break;
-               }
-               
-               $ok = false;
-               while ( !$ok )
-               {
-                       // generate a random key
-                       srand((double)microtime()*1000000);
-                       $key = $this->hash(uniqid(rand(), true));
-                       
-                       // attempt to add entry in database
-                       // add in database as non-active
-                       $query = 'INSERT INTO ' . sql_table('activation'). ' (vkey, vtime, vmember, vtype, vextra) ';
-                       $query .= 'VALUES (\'' . sql_real_escape_string($key). '\', \'' . date('Y-m-d H:i:s',time()) . '\', \'' . intval($this->getID()). '\', \'' . sql_real_escape_string($type). '\', \'' . sql_real_escape_string($extra). '\')';
-                       if ( sql_query($query) )
-                               $ok = true;
-               }
-               
-               // mark member as not allowed to log in
-               if ( !$canLoginWhileActive )
-               {
-                       $this->setCanLogin(0);
-                       $this->write();
-               }
-               
-               // return the key
-               return $key;
-       }
-       
-       /*
-        * Inidicates that an activation link has been clicked and any forms displayed
-        * there have been successfully filled out.
-        * @author dekarma
-        */
-       function activate($key)
-       {
-               // get activate info
-               $info = MEMBER::getActivationInfo($key);
-               
-               // no active key
-               if ( !$info )
-               {
-                       return false;
-               }
-               
-               switch ( $info->vtype )
-               {
-                       case 'forgot':
-                               // nothing to do
-                               break;
-                       case 'register':
-                               // set canlogin value
-                               global $CONF;
-                               sql_query('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($CONF['NewMemberCanLogon']). ' WHERE mnumber=' . intval($info->vmember));
-                               break;
-                       case 'addresschange':
-                               // reset old 'canlogin' value
-                               list($oldEmail, $oldCanLogin) = i18n::explode('/', $info->vextra);
-                               sql_query('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($oldCanLogin). ' WHERE mnumber=' . intval($info->vmember));
-                               break;
-               }
-               
-               // delete from activation table
-               sql_query('DELETE FROM ' . sql_table('activation') . ' WHERE vkey=\'' . sql_real_escape_string($key) . '\'');
-               
-               // success!
-               return true;
-       }
-       
-       /**
-        * Cleans up entries in the activation table. All entries older than 2 days are removed.
-        * (static)
-        *
-        * @author dekarma
-        */
-       public function cleanupActivationTable()
-       {
-               $actdays = 2;
-               if ( isset($CONF['ActivationDays']) && intval($CONF['ActivationDays']) > 0 )
-               {
-                       $actdays = intval($CONF['ActivationDays']);
-               }
-               else
-               {
-                       $CONF['ActivationDays'] = 2;
-               }
-               $boundary = time() - (60 * 60 * 24 * $actdays);
-               
-               // 1. walk over all entries, and see if special actions need to be performed
-               $res = sql_query('SELECT * FROM ' . sql_table('activation') . ' WHERE vtime < \'' . date('Y-m-d H:i:s',$boundary) . '\'');
-               
-               while ( $o = sql_fetch_object($res) )
-               {
-                       switch ( $o->vtype )
-                       {
-                               case 'register':
-                                       // delete all information about this site member. registration is undone because there was
-                                       // no timely activation
-                                       include_once($DIR_LIBS . 'ADMIN.php');
-                                       ADMIN::deleteOneMember(intval($o->vmember));
-                                       break;
-                               case 'addresschange':
-                                       // revert the e-mail address of the member back to old address
-                                       list($oldEmail, $oldCanLogin) = i18n::explode('/', $o->vextra);
-                                       sql_query('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($oldCanLogin). ', memail=\'' . sql_real_escape_string($oldEmail). '\' WHERE mnumber=' . intval($o->vmember));
-                                       break;
-                               case 'forgot':
-                                       // delete the activation link and ignore. member can request a new password using the
-                                       // forgot password link
-                                       break;
-                       }
-               }
-               
-               // 2. delete activation entries for real
-               sql_query('DELETE FROM ' . sql_table('activation') . ' WHERE vtime < \'' . date('Y-m-d H:i:s',$boundary) . '\'');
-       }
-}
+<?php\r
+\r
+/* \r
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)\r
+ * Copyright (C) 2002-2009 The Nucleus Group\r
+ * \r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ * (see nucleus/documentation/index.html#license for more info)\r
+ */\r
+/**\r
+ * A class representing site members\r
+ * \r
+ * @license http://nucleuscms.org/license.txt GNU General Public License\r
+ * @copyright Copyright (C) 2002-2009 The Nucleus Group\r
+ * @version $Id: MEMBER.php 1616 2012-01-08 09:48:15Z sakamocchi $\r
+ */\r
+class Member\r
+{\r
+       // 1 when authenticated, 0 when not\r
+       public $loggedin = 0;\r
+       public $password;               // not the actual password, but rather a MD5 hash\r
+       private $algorism = 'md5';\r
+       \r
+       public $cookiekey;              // value that should also be in the client cookie to allow authentication\r
+       private $cookie_salt = FALSE;\r
+       \r
+       // member info\r
+       public $id = -1;\r
+       public $realname;\r
+       public $displayname;\r
+       public $email;\r
+       public $url;\r
+       public $admin = 0;                      // (either 0 or 1)\r
+       public $canlogin = 0;           // (either 0 or 1)\r
+       public $notes;\r
+       public $autosave = 1;           // if the member use the autosave draft function\r
+       private $locale = '';\r
+       \r
+       /**\r
+        * Member::__construct()\r
+        * Constructor for a member object\r
+        * \r
+        * @param       Void\r
+        * @return      Void\r
+        * \r
+        */\r
+       public function __construct()\r
+       {\r
+               return;\r
+       }\r
+       \r
+       /**\r
+        * Member::createFromName()\r
+        * Create a member object for a given displayname\r
+        * \r
+        * @static\r
+        * @param       String  $displayname    login name\r
+        * @return      Object  member object\r
+        * \r
+        */\r
+       public static function &createFromName($displayname)\r
+       {\r
+               $mem = new Member();\r
+               $mem->readFromName($displayname);\r
+               return $mem;\r
+       }\r
+       \r
+       /**\r
+        * Member::createFromID()\r
+        * Create a member object for a given ID\r
+        * \r
+        * @static\r
+        * @param       Integer $id     id for member\r
+        */\r
+       public static function &createFromID($id)\r
+       {\r
+               $mem = new Member();\r
+               $mem->readFromID($id);\r
+               return $mem;\r
+       }\r
+       \r
+       /**\r
+        * Member::readFromName()\r
+        * Read member table in database\r
+        * \r
+        * @param       String  $displayname    login name\r
+        * @return      Object  SQL resource\r
+        * \r
+        */\r
+       public function readFromName($displayname)\r
+       {\r
+               return $this->read('mname='.DB::quoteValue($displayname));\r
+       }\r
+       \r
+       /**\r
+        * Member::readFromID()\r
+        * Read member table in database\r
+        * \r
+        * @param       Integer $id     id for member\r
+        * @return      Object  SQL resource\r
+        * \r
+        */\r
+       public function readFromID($id)\r
+       {\r
+               return $this->read("mnumber=" . intval($id));\r
+       }\r
+       \r
+       /**\r
+        * Member::hash()\r
+        * hash the target string\r
+        * \r
+        * @param       String  $string target string\r
+        * @return      Void    hashed string\r
+        */\r
+       public function hash($string)\r
+       {\r
+               switch ( $this->algorism )\r
+               {\r
+                       case 'md5':\r
+                       default:\r
+                               $string = md5($string);\r
+               }\r
+               return $string;\r
+       }\r
+       \r
+       /**\r
+        * Member::set_cookie_salt()\r
+        * \r
+        * @param       integer $key    secureCookieKey value\r
+        * @return      void\r
+        * \r
+        */\r
+       private function set_cookie_salt($key = 0)\r
+       {\r
+               if ( !$key )\r
+               {\r
+                       $key = 24;\r
+               }\r
+               \r
+               switch( $key )\r
+               {\r
+                       case 8:\r
+                               $this->cookie_salt = preg_replace('/\.[0-9]+\.[0-9]+\.[0-9]+$/', '', serverVar('REMOTE_ADDR'));\r
+                               break;\r
+                       case 16:\r
+                               $this->cookie_salt = preg_replace('/\.[0-9]+\.[0-9]+$/', '', serverVar('REMOTE_ADDR'));\r
+                               break;\r
+                       case 24:\r
+                               $this->cookie_salt = preg_replace('/\.[0-9]+$/', '', serverVar('REMOTE_ADDR'));\r
+                               break;\r
+                       case 32:\r
+                               $this->cookie_salt = serverVar('REMOTE_ADDR');\r
+                               break;\r
+                       default:\r
+                               $this->cookie_salt = 'none';\r
+               }\r
+               return;\r
+       }\r
+       \r
+       /**\r
+        * Member::login()\r
+        * Tries to login as a given user.\r
+        * Returns true when succeeded, returns false when failed\r
+        * 3.40 adds CustomLogin event\r
+        * \r
+        * @param       String  $login  login name for member\r
+        * @param       String  $password       password for member\r
+        * @param       Integer $shared whether the user agent is shared or not\r
+        * \r
+        */\r
+       public function login($login, $password, $shared=1)\r
+       {\r
+               global $CONF, $errormessage, $manager;\r
+               \r
+               /* TODO: validation for $login, $password, $shared */\r
+               if ( $login == '' || $password == '' )\r
+               {\r
+                       return 0;\r
+               }\r
+               /* limiting the length of password to avoid hash collision */\r
+               $password=i18n::substr($password, 0, 40);\r
+               \r
+               /* \r
+                * generate cookie salt from secure cookie key settings\r
+               * (either 'none', 0, 8, 16, 24, or 32)\r
+               */\r
+               if ( !$this->cookie_salt )\r
+               {\r
+                       $salt = 0;\r
+                       if ( array_key_exists('secureCookieKey', $CONF) )\r
+                       {\r
+                               $salt = $CONF['secureCookieKey'];\r
+                       }\r
+                       $this->set_cookie_salt($salt);\r
+               }\r
+               \r
+               $success = 0;\r
+               $allowlocal = 1;\r
+               $manager->notify('CustomLogin', array('login' => &$login, 'password'=>&$password, 'success'=>&$success, 'allowlocal'=>&$allowlocal));\r
+               \r
+               $this->loggedin = 0;\r
+               if ( $success )\r
+               {\r
+                       $this->loggedin = ( $this->readFromName($login) );\r
+               }\r
+               elseif ( $allowlocal )\r
+               {\r
+                       $this->loggedin = ( $this->readFromName($login) && $this->checkPassword($password) );\r
+               }\r
+               \r
+               /* login failed */\r
+               if ( !$this->loggedin )\r
+               {\r
+                       $trimlogin = trim($login);\r
+                       if ( empty($trimlogin) )\r
+                       {\r
+                               $errormessage = "Please enter a username.";\r
+                       }\r
+                       else\r
+                       {\r
+                               $errormessage = 'Login failed for ' . $login;\r
+                       }\r
+                       $manager->notify('LoginFailed', array('username' => $login) );\r
+                       ActionLog::add(INFO, $errormessage);\r
+               }\r
+               /* login success */\r
+               else\r
+               {\r
+                       /* For lower compatibility */\r
+                       if ( strlen($this->password) === 32 )\r
+                       {\r
+                               $this->password = $this->hash($password);\r
+                       }\r
+                       \r
+                       $this->newCookieKey();\r
+                       $this->setCookies($shared);\r
+                       \r
+                       if ( $this->cookie_salt !== 'none' )\r
+                       {\r
+                               /* secure cookie key */\r
+                               $this->setCookieKey($this->hash($this->getCookieKey() . $this->cookie_salt));\r
+                               $this->write();\r
+                       }\r
+                       \r
+                       $errormessage = '';\r
+                       $manager->notify('LoginSuccess', array('member' => &$member, 'username' => $login) );\r
+                       ActionLog::add(INFO, "Login successful for $login (sharedpc=$shared)");\r
+               }\r
+               \r
+               return $this->loggedin;\r
+       }\r
+       \r
+       /**\r
+        * Member::cookielogin()\r
+        * Login using cookie key\r
+        * \r
+        * @param       String  $login  not used\r
+        * @param       String  $cookiekey      not used\r
+        * @return      Boolean login or not\r
+        */\r
+       public function cookielogin($login='', $cookiekey='')\r
+       {\r
+               global $CONF, $manager;\r
+               \r
+               if ( !headers_sent() && cookieVar("{$CONF['CookiePrefix']}user") )\r
+               {\r
+                       /* Cookie Authentication */\r
+                       $ck = cookieVar("{$CONF['CookiePrefix']}loginkey");\r
+                               \r
+                       /* TODO: validation for each cookie values */\r
+                               \r
+                       /* limiting the length of password to avoid hash collision */\r
+                       $ck = i18n::substr($ck,0,32);\r
+                               \r
+                       /* \r
+                        * generate cookie salt from secure cookie key settings\r
+                       * (either 'none', 0, 8, 16, 24, or 32)\r
+                       */\r
+                       if ( !$this->cookie_salt )\r
+                       {\r
+                               $salt = 0;\r
+                               if ( array_key_exists('secureCookieKey', $CONF) )\r
+                               {\r
+                                       $salt = $CONF['secureCookieKey'];\r
+                               }\r
+                               $this->set_cookie_salt($salt);\r
+                       }\r
+                       \r
+                       if ( $this->cookie_salt !== 'none' )\r
+                       {\r
+                               $ck = $this->hash($ck . $this->cookie_salt);\r
+                       }\r
+                       $this->loggedin = ( $this->readFromName(cookieVar("{$CONF['CookiePrefix']}user")) && $this->checkCookieKey($ck) );\r
+                       unset($ck);\r
+                               \r
+                       /* renew cookies when not on a shared computer */\r
+                       if ( $this->loggedin && (cookieVar($CONF['CookiePrefix'] . 'sharedpc') != 1) )\r
+                       {\r
+                               $this->setCookieKey(cookieVar("{$CONF['CookiePrefix']}loginkey"));\r
+                               $this->setCookies();\r
+                       }\r
+               }\r
+               return $this->loggedin;\r
+       }\r
+       \r
+       /**\r
+        * Member::logout()\r
+        * logout and expire cookie\r
+        * \r
+        * @param       Void\r
+        * @return      Void\r
+        */\r
+       public function logout()\r
+       {\r
+               global $CONF, $manager;\r
+               \r
+               if ( !headers_sent() && cookieVar("{$CONF['CookiePrefix']}user") )\r
+               {\r
+                       /* remove cookies on logout */\r
+                       setcookie("{$CONF['CookiePrefix']}user", '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);\r
+                       setcookie("{$CONF['CookiePrefix']}loginkey", '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);\r
+                       $manager->notify('Logout', array('username' => cookieVar("{$CONF['CookiePrefix']}user") ) );\r
+               }\r
+               \r
+               $this->loggedin = 0;\r
+               return;\r
+       }\r
+       \r
+       /**\r
+        * Member::isLoggedIn()\r
+        * return member is loggedin or not\r
+        * \r
+        * @param       Void\r
+        * @return      Void\r
+        */\r
+       public function isLoggedIn()\r
+       {\r
+               return $this->loggedin;\r
+       }\r
+       \r
+       /**\r
+        * MEMBER:read()\r
+        * Read member information from the database\r
+        * \r
+        * @param       String  $where  where statement\r
+        * @return      Resource        SQL resource\r
+        * \r
+        */\r
+       public function read($where)\r
+       {\r
+               // read info\r
+               $query =  'SELECT * FROM '.sql_table('member') . ' WHERE ' . $where;\r
+               \r
+               $row = DB::getRow($query);\r
+               \r
+               $this->setRealName($row['mrealname']);\r
+               $this->setEmail($row['memail']);\r
+               $this->password = $row['mpassword'];\r
+               $this->setCookieKey($row['mcookiekey']);\r
+               $this->setURL($row['murl']);\r
+               $this->setDisplayName($row['mname']);\r
+               $this->setAdmin($row['madmin']);\r
+               $this->id = $row['mnumber'];\r
+               $this->setCanLogin($row['mcanlogin']);\r
+               $this->setNotes($row['mnotes']);\r
+               $this->setLocale($row['mlocale']);\r
+               $this->setAutosave($row['mautosave']);\r
+               \r
+               return $row ? TRUE : FALSE;\r
+       }\r
+       \r
+       /**\r
+        * Member::isBlogAdmin()\r
+        * Returns true if member is an admin for the given blog\r
+        * (returns false if not a team member)\r
+        * \r
+        * @param       Integer $blogid weblog id\r
+        * @return      Integer weblog admin or not\r
+        * \r
+        */\r
+       public function isBlogAdmin($blogid)\r
+       {\r
+               $query = 'SELECT tadmin FROM '.sql_table('team').' WHERE'\r
+               . ' tblog=' . intval($blogid)\r
+               . ' and tmember='. $this->getID();\r
+               $res = DB::getValue($query);\r
+               if ( $res )\r
+                       return ($res == 1);\r
+               else\r
+                       return 0;\r
+       }\r
+       \r
+       /**\r
+        * Member::blogAdminRights()\r
+        * \r
+        * @param       integer $blogid ID of target weblog\r
+        * @return      boolean whether to have admin rights to the weblog or not\r
+        * \r
+        */\r
+       public function blogAdminRights($blogid)\r
+       {\r
+               return ($this->isAdmin() || $this->isBlogAdmin($blogid));\r
+       }\r
+       \r
+       /**\r
+        * Member::teamRights()\r
+        * \r
+        * @param       integer $blogid ID of target weblog\r
+        * @return      boolean whether to have admin right to the weblog or not\r
+        * \r
+        */\r
+       public function teamRights($blogid)\r
+       {\r
+               return ($this->isAdmin() || $this->isTeamMember($blogid));\r
+       }\r
+       \r
+       /**\r
+        * Member::isTeamMember()\r
+        * Returns true if this member is a team member of the given blog\r
+        * \r
+        * @param       integer $blogid ID of target weblog\r
+        * @return      boolean whether to join the weblog or not\r
+        * \r
+        */\r
+       public function isTeamMember($blogid)\r
+       {\r
+               $query = 'SELECT * FROM '.sql_table('team').' WHERE'\r
+                          . ' tblog=' . intval($blogid)\r
+                          . ' and tmember='. $this->getID();\r
+               $res = DB::getResult($query);\r
+               return ($res->rowCount() != 0);\r
+       }\r
+       \r
+       /**\r
+        * Member::canAddItem()\r
+        * \r
+        * @param       integer $catid  ID of target category\r
+        * @return      boolean whether to be able to add items to the category or not\r
+        * \r
+        */\r
+       public function canAddItem($catid)\r
+       {\r
+               global $manager;\r
+               \r
+               // if this is a 'newcat' style newcat\r
+               // no blog admin of destination blog -> NOK\r
+               // blog admin of destination blog -> OK\r
+               if ( i18n::strpos($catid,'newcat') === 0 )\r
+               {\r
+                       // get blogid\r
+                       list($blogid) = sscanf($catid,"newcat-%d");\r
+                       return $this->blogAdminRights($blogid);\r
+               }\r
+               \r
+               // category does not exist -> NOK\r
+               if ( !$manager->existsCategory($catid) )\r
+               {\r
+                       return 0;\r
+               }\r
+               \r
+               $blogid = getBlogIDFromCatID($catid);\r
+               \r
+               // no team rights for blog -> NOK\r
+               if (!$this->teamRights($blogid))\r
+               {\r
+                       return 0;\r
+               }\r
+               \r
+               // all other cases: OK\r
+               return 1;\r
+       }\r
+       \r
+       /**\r
+        * Member::canAlterComment()\r
+        * Returns true if this member can edit/delete a commentitem. This can be in the\r
+        * following cases:\r
+        *        - member is a super-admin\r
+        *   - member is the author of the comment\r
+        *   - member is admin of the blog associated with the comment\r
+        *   - member is author of the item associated with the comment\r
+        * \r
+        * @param       integer $commentid      ID of target comment\r
+        * @return      boolean delete/edit the comment or not\r
+        * \r
+        */\r
+       public function canAlterComment($commentid)\r
+       {\r
+               if ( $this->isAdmin() )\r
+               {\r
+                       return 1;\r
+               }\r
+               \r
+               $query =  'SELECT citem as itemid, iblog as blogid, cmember as cauthor, iauthor'\r
+                          . ' FROM '.sql_table('comment') .', '.sql_table('item').', '.sql_table('blog')\r
+                          . ' WHERE citem=inumber and iblog=bnumber and cnumber=' . intval($commentid);\r
+               $res = DB::getRow($query);\r
+               \r
+               return ($res['cauthor'] == $this->getID()) or $this->isBlogAdmin($res['blogid']) or ($res['iauthor'] == $this->getID());\r
+       }\r
+       \r
+       /**\r
+        * Member::canAlterItem()\r
+        * Returns true if this member can edit/delete an item. This is true in the following\r
+        * cases: - member is a super-admin\r
+        *             - member is the author of the item\r
+        *        - member is admin of the the associated blog\r
+        * \r
+        * @param       integer $itemid ID of target item\r
+        * @return      boolean delete/edit the item or not\r
+        * \r
+        */\r
+       public function canAlterItem($itemid)\r
+       {\r
+               if ($this->isAdmin()) return 1;\r
+               \r
+               $query =  'SELECT iblog, iauthor FROM '.sql_table('item').' WHERE inumber=' . intval($itemid);\r
+               $res = DB::getRow($query);\r
+               return ($res['iauthor'] == $this->getID()) or $this->isBlogAdmin($res['iblog']);\r
+       }\r
+       \r
+       /**\r
+        * Member::canBeDeleted()\r
+        * Return true if member can be deleted. This means that there are no items posted by the member left\r
+        * \r
+        * @param       void\r
+        * @return      boolean whether there is no items or exists\r
+        * \r
+        */\r
+       public function canBeDeleted()\r
+       {\r
+               $res = DB::getResult('SELECT * FROM '.sql_table('item').' WHERE iauthor=' . $this->getID());\r
+               return ( $res->rowCount() == 0 );\r
+       }\r
+       \r
+       /**\r
+        * Member::canUpdateItem()\r
+        * returns true if this member can move/update an item to a given category,\r
+        * false if not (see comments fot the tests that are executed)\r
+        * \r
+        * @param       integer $itemid\r
+        * @param       string  $newcat (can also be of form 'newcat-x' with x=blogid)\r
+        * @return      boolean whether being able to update the item or not\r
+        * \r
+        */\r
+       public function canUpdateItem($itemid, $newcat)\r
+       {\r
+               global $manager;\r
+               \r
+               // item does not exists -> NOK\r
+               if ( !$manager->existsItem($itemid,1,1) )\r
+               {\r
+                       return 0;\r
+               }\r
+               \r
+               // cannot alter item -> NOK\r
+               if (!$this->canAlterItem($itemid))\r
+               {\r
+                       return 0;\r
+               }\r
+               \r
+               // if this is a 'newcat' style newcat\r
+               // no blog admin of destination blog -> NOK\r
+               // blog admin of destination blog -> OK\r
+               if ( i18n::strpos($newcat, 'newcat') === 0 )\r
+               {\r
+                       // get blogid\r
+                       list($blogid) = sscanf($newcat, 'newcat-%d');\r
+                       return $this->blogAdminRights($blogid);\r
+               }\r
+               \r
+               // category does not exist -> NOK\r
+               if (!$manager->existsCategory($newcat))\r
+               {\r
+                       return 0;\r
+               }\r
+               \r
+               // get item\r
+               $item =& $manager->getItem($itemid,1,1);\r
+               \r
+               // old catid = new catid -> OK\r
+               if ($item['catid'] == $newcat)\r
+               {\r
+                       return 1;\r
+               }\r
+               \r
+               // not a valid category -> NOK\r
+               $validCat = DB::getValue('SELECT COUNT(*) AS result FROM '.sql_table('category').' WHERE catid='.intval($newcat));\r
+               if ( !$validCat )\r
+               {\r
+                       return 0;\r
+               }\r
+               \r
+               // get destination blog\r
+               $source_blogid = getBlogIDFromItemID($itemid);\r
+               $dest_blogid = getBlogIDFromCatID($newcat);\r
+               \r
+               // not a team member of destination blog -> NOK\r
+               if ( !$this->teamRights($dest_blogid) )\r
+               {\r
+                       return 0;\r
+               }\r
+               \r
+               // if member is author of item -> OK\r
+               if ( $item['authorid'] == $this->getID() )\r
+               {\r
+                       return 1;\r
+               }\r
+               \r
+               // if member has admin rights on both blogs: OK\r
+               if ( ($this->blogAdminRights($dest_blogid)) && ($this->blogAdminRights($source_blogid)) )\r
+               {\r
+                       return 1;\r
+               }\r
+               \r
+               // all other cases: NOK\r
+               return 0;\r
+       }\r
+       \r
+       /**\r
+        * Member::setCookies()\r
+        * Sets the cookies for the member\r
+        * \r
+        * @param boolean       $shared set this to 1 when using a shared computer. Cookies will expire\r
+        *                              at the end of the session in this case.\r
+        * @return      void\r
+        * \r
+        */\r
+       public function setCookies($shared = 0)\r
+       {\r
+               global $CONF;\r
+               \r
+               if ( $CONF['SessionCookie'] || $shared )\r
+               {\r
+                       $lifetime = 0;\r
+               }\r
+               else\r
+               {\r
+                       $lifetime = time()+2592000;\r
+               }\r
+               \r
+               setcookie($CONF['CookiePrefix'] . 'user', $this->getDisplayName(), $lifetime, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);\r
+               setcookie($CONF['CookiePrefix'] . 'loginkey', $this->getCookieKey(), $lifetime, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);\r
+               \r
+               // make sure cookies on shared pcs don't get renewed\r
+               if ( $shared )\r
+               {\r
+                       setcookie($CONF['CookiePrefix'] .'sharedpc', '1',$lifetime,$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);\r
+               }\r
+               return;\r
+       }\r
+       \r
+       /**\r
+        * Member::sendActivationLink()\r
+        * Send activation mail\r
+        * \r
+        * @param       string  $type   activation type\r
+        * @param       string  $extra  extra info\r
+        * @return      void\r
+        */\r
+       public function sendActivationLink($type, $extra='')\r
+       {\r
+               global $CONF;\r
+               \r
+               if ( !isset($CONF['ActivationDays']) )\r
+               {\r
+                       $CONF['ActivationDays'] = 2;\r
+               }\r
+               \r
+               // generate key and URL\r
+               $key = $this->generateActivationEntry($type, $extra);\r
+               $url = $CONF['AdminURL'] . 'index.php?action=activate&key=' . $key;\r
+               \r
+               // choose text to use in mail\r
+               switch ( $type )\r
+               {\r
+                       case 'register':\r
+                               $message = _ACTIVATE_REGISTER_MAIL;\r
+                               $subject = _ACTIVATE_REGISTER_MAILTITLE;\r
+                               break;\r
+                       case 'forgot':\r
+                               $message = _ACTIVATE_FORGOT_MAIL;\r
+                               $subject = _ACTIVATE_FORGOT_MAILTITLE;\r
+                               break;\r
+                       case 'addresschange':\r
+                               $message = _ACTIVATE_CHANGE_MAIL;\r
+                               $subject = _ACTIVATE_CHANGE_MAILTITLE;\r
+                               break;\r
+                       default;\r
+               }\r
+               \r
+               // fill out variables in text\r
+               $aVars = array(\r
+                       'siteName' => $CONF['SiteName'],\r
+                       'siteUrl' => $CONF['IndexURL'],\r
+                       'memberName' => $this->getDisplayName(),\r
+                       'activationUrl' => $url,\r
+                       'activationDays' => $CONF['ActivationDays']\r
+               );\r
+               \r
+               $message = Template::fill($message, $aVars);\r
+               $subject = Template::fill($subject, $aVars);\r
+               \r
+               // send mail\r
+               NOTIFICATION::mail($this->getEmail(), $subject ,$message, $CONF['AdminEmail'], i18n::get_current_charset());\r
+               \r
+               ActionLog::add(INFO, _ACTIONLOG_ACTIVATIONLINK . ' (' . $this->getDisplayName() . ' / type: ' . $type . ')');\r
+               return;\r
+       }\r
+       \r
+       /**\r
+        * Member::getAdminBlogs()\r
+        * Returns an array of all blogids for which member has admin rights\r
+        * \r
+        * @param       void\r
+        * @return      array   weblog IDs in which this member has admin rights\r
+        * \r
+        */\r
+       public function getAdminBlogs()\r
+       {\r
+               $blogs = array();\r
+               \r
+               if ($this->isAdmin())\r
+               {\r
+                       $query = 'SELECT bnumber as blogid from '.sql_table('blog');\r
+               }\r
+               else\r
+               {\r
+                       $query = 'SELECT tblog as blogid from '.sql_table('team').' where tadmin=1 and tmember=' . $this->getID();\r
+               }\r
+               \r
+               $res = DB::getResult($query);\r
+               if ( $res->rowCount() > 0 )\r
+               {\r
+                       foreach ( $res as $row )\r
+                       {\r
+                               array_push($blogs, $row['blogid']);\r
+                       }\r
+               }\r
+               return $blogs;\r
+       }\r
+       \r
+       /**\r
+        * Member::getTeamBlogs()\r
+        * Returns an array of all blogids for which member has team rights\r
+        * \r
+        * @param       boolean $incAdmin       whether checking weblog admin rights or not\r
+        * @return      array   weblog IDs in which this member join\r
+        * \r
+        */\r
+       public function getTeamBlogs($incAdmin = 1)\r
+       {\r
+               $incAdmin = intval($incAdmin);\r
+               $blogs = array();\r
+               \r
+               if ( $this->isAdmin() && $incAdmin )\r
+               {\r
+                       $query = 'SELECT bnumber as blogid from '.sql_table('blog');\r
+               }\r
+               else\r
+               {\r
+                       $query = 'SELECT tblog as blogid from '.sql_table('team').' where tmember=' . $this->getID();\r
+               }\r
+               \r
+               $res = DB::getResult($query);\r
+               if ( $res->rowCount() > 0 )\r
+               {\r
+                       foreach ( $res as $row )\r
+                       {\r
+                               array_push($blogs, $row['blogid']);\r
+                       }\r
+               }\r
+               return $blogs;\r
+       }\r
+       \r
+       /**\r
+        * Member::getNotifyFromMailAddress()\r
+        * \r
+        * Returns an email address from which notification of commenting/karma voting can\r
+        * be sent. A suggestion can be given for when the member is not logged in\r
+        * \r
+        * @param       String  $suggest\r
+        * @return      String  mail address or suggestion\r
+        */\r
+       public function getNotifyFromMailAddress($suggest = "")\r
+       {\r
+               global $CONF;\r
+               if ( $this->isLoggedIn() )\r
+               {\r
+                       return $this->getDisplayName() . " <" . $this->getEmail() . ">";\r
+               }\r
+               else if ( NOTIFICATION::address_validation($suggest) )\r
+               {\r
+                       return $suggest;\r
+               }\r
+               return $CONF['AdminEmail'];\r
+       }\r
+       \r
+       /**\r
+        * Member::write()\r
+        * Write data to database\r
+        * \r
+        * @param       void\r
+        * @return      void\r
+        * \r
+        */\r
+       public function write()\r
+       {\r
+               $query =  'UPDATE '.sql_table('member')\r
+                       . ' SET mname=' . DB::quoteValue($this->displayname) . ', '\r
+                          . 'mrealname='. DB::quoteValue($this->realname) . ', '\r
+                          . 'mpassword='. DB::quoteValue($this->password) . ', '\r
+                          . 'mcookiekey='. DB::quoteValue($this->cookiekey) . ', '\r
+                          . 'murl=' . DB::quoteValue($this->url) . ', '\r
+                          . 'memail=' . DB::quoteValue($this->email) . ', '\r
+                          . 'madmin=' . intval($this->admin) . ', '\r
+                          . 'mnotes=' . DB::quoteValue($this->notes) . ', '\r
+                          . 'mcanlogin=' . intval($this->canlogin) . ', '\r
+                          . 'mlocale=' . DB::quoteValue($this->locale) . ', '\r
+                          . 'mautosave=' . intval($this->autosave) . ' '\r
+                       . 'WHERE mnumber=' . intval($this->id);\r
+               DB::execute($query);\r
+               return;\r
+       }\r
+       \r
+       public function checkCookieKey($key)\r
+       {\r
+               return ( ($key != '') && ( $key == $this->getCookieKey() ) );\r
+       }\r
+       \r
+       public function checkPassword($pw)\r
+       {\r
+               /* for lower compatibility (md5) */\r
+               if ( strlen($this->password) === 32 )\r
+               {\r
+                       return (md5($pw) == $this->password);\r
+               }\r
+               return ($this->hash($pw) == $this->password);\r
+       }\r
+       \r
+       public function getRealName()\r
+       {\r
+               return $this->realname;\r
+       }\r
+       \r
+       public function setRealName($name)\r
+       {\r
+               $this->realname = $name;\r
+       }\r
+       \r
+       public function getEmail()\r
+       {\r
+               return $this->email;\r
+       }\r
+       \r
+       public function setEmail($email)\r
+       {\r
+               $this->email = $email;\r
+       }\r
+       \r
+       public function getPassword()\r
+       {\r
+               return $this->password;\r
+       }\r
+       \r
+       public function setPassword($pwd)\r
+       {\r
+               $this->password = $this->hash($pwd);\r
+       }\r
+       \r
+       public function getCookieKey()\r
+       {\r
+               return $this->cookiekey;\r
+       }\r
+       \r
+       /**\r
+        * Member::newCookieKey()\r
+        * Generate new cookiekey, save it, and return it\r
+        * \r
+        * @param       void\r
+        * @return      void\r
+        * \r
+        */\r
+       public function newCookieKey()\r
+       {\r
+               mt_srand( (double) microtime() * 1000000);\r
+               $this->cookiekey = $this->hash(uniqid(mt_rand()));\r
+               $this->write();\r
+               return $this->cookiekey;\r
+       }\r
+       \r
+       public function setCookieKey($val)\r
+       {\r
+               $this->cookiekey = $val;\r
+       }\r
+       \r
+       public function getURL()\r
+       {\r
+               return $this->url;\r
+       }\r
+       \r
+       public function setURL($site)\r
+       {\r
+               $this->url = $site;\r
+       }\r
+       \r
+       public function getLocale()\r
+       {\r
+               return $this->locale;\r
+       }\r
+       \r
+       public function setLocale($locale)\r
+       {\r
+               if ( !preg_match('#^(.+)_(.+)_(.+)$#', $locale)\r
+                && ($locale = i18n::convert_old_language_file_name_to_locale($locale)) === FALSE )\r
+               {\r
+                       $locale = '';\r
+               }\r
+               $this->locale = $locale;\r
+               return;\r
+       }\r
+       \r
+       public function setDisplayName($nick)\r
+       {\r
+               $this->displayname = $nick;\r
+       }\r
+       \r
+       public function getDisplayName()\r
+       {\r
+               return $this->displayname;\r
+       }\r
+       \r
+       public function isAdmin()\r
+       {\r
+               return $this->admin;\r
+       }\r
+       \r
+       public function setAdmin($val)\r
+       {\r
+               $this->admin = $val;\r
+       }\r
+       \r
+       public function canLogin()\r
+       {\r
+               return $this->canlogin;\r
+       }\r
+       \r
+       public function setCanLogin($val)\r
+       {\r
+               $this->canlogin = $val;\r
+       }\r
+       \r
+       public function getNotes()\r
+       {\r
+               return $this->notes;\r
+       }\r
+       \r
+       public function setNotes($val)\r
+       {\r
+               $this->notes = $val;\r
+       }\r
+       \r
+       public function getAutosave()\r
+       {\r
+               return $this->autosave;\r
+       }\r
+       \r
+       public function setAutosave($val)\r
+       {\r
+               $this->autosave = $val;\r
+               return;\r
+       }\r
+       \r
+       /**\r
+        * Member::getID()\r
+        * \r
+        * @param       void\r
+        * @return      integer id of this member object\r
+        * \r
+        */\r
+       public function getID()\r
+       {\r
+               return $this->id;\r
+       }\r
+       \r
+       /**\r
+        * Member::exists()\r
+        * Returns true if there is a member with the given login name\r
+        * \r
+        * @static\r
+        * @param       string  $name   target name\r
+        * @return      boolean whether target name exists or not\r
+        */\r
+       public static function exists($name)\r
+       {\r
+               $r = DB::getResult('SELECT * FROM ' . sql_table('member') . ' WHERE mname=' . DB::quoteValue($name));\r
+               return ( $r->rowCount() != 0 );\r
+       }\r
+       \r
+       /**\r
+        * Member::existsID()\r
+        * Returns true if there is a member with the given ID\r
+        * \r
+        * @static\r
+        * @param       integer $id     target id\r
+        * @return      boolean whether target id exists or not\r
+        * \r
+        */\r
+       public static function existsID($id)\r
+       {\r
+               $r = DB::getResult('SELECT * FROM ' . sql_table('member') . ' WHERE mnumber=' . intval($id));\r
+               return ( $r->rowCount() != 0 );\r
+       }\r
+       \r
+       /**\r
+        * Member::isNameProtected()\r
+        *  Checks if a username is protected.\r
+        *  If so, it can not be used on anonymous comments\r
+        * \r
+        * @param       string  $name   target name\r
+        * @return      boolean whether the name exists or not\r
+        * \r
+        */\r
+       public function isNameProtected($name)\r
+       {\r
+               // extract name\r
+               $name = strip_tags($name);\r
+               $name = trim($name);\r
+               return self::exists($name);\r
+       }\r
+       \r
+       /**\r
+        * Member::create()\r
+        * Adds a new member\r
+        * \r
+        * @static\r
+        * @param       String  $name\r
+        * @param       String  $realname\r
+        * @param       String  $password\r
+        * @param       String  $email\r
+        * @param       String  $url\r
+        * @param       String  $admin\r
+        * @param       String  $canlogin\r
+        * @param       String  $notes\r
+        * @return      String  1 if success, others if fail\r
+        */\r
+       static public function create($name, $realname, $password, $email, $url, $admin, $canlogin, $notes)\r
+       {\r
+               if ( !NOTIFICATION::address_validation($email) )\r
+               {\r
+                       return _ERROR_BADMAILADDRESS;\r
+               }\r
+               \r
+               /* TODO: this method should be in MEMBER class, not globalfunctions */\r
+               if ( !isValidDisplayName($name) )\r
+               {\r
+                       return _ERROR_BADNAME;\r
+               }\r
+               \r
+               if ( self::exists($name) )\r
+               {\r
+                       return _ERROR_NICKNAMEINUSE;\r
+               }\r
+               \r
+               if ( !$realname )\r
+               {\r
+                       return _ERROR_REALNAMEMISSING;\r
+               }\r
+               \r
+               /* TODO: check the number of characters */\r
+               if ( !$password )\r
+               {\r
+                       return _ERROR_PASSWORDMISSING;\r
+               }\r
+               \r
+               /* \r
+                *  begin if: sometimes user didn't prefix the URL with http:// or https://,\r
+                *  this cause a malformed URL. Let's fix it.\r
+                */\r
+               \r
+               if ( !preg_match('#^https?://#', $url) )\r
+               {\r
+                       $url = 'http://' . $url;\r
+               }\r
+               \r
+               $name           = DB::quoteValue($name);\r
+               $realname       = DB::quoteValue($realname);\r
+               /* NOTE: hashed password is automatically updated if the length is 32 bytes when logging in */\r
+               $password       = DB::quoteValue(md5($password));\r
+               $email          = DB::quoteValue($email);\r
+               $url            = DB::quoteValue($url);\r
+               $admin          = (integer) $admin;\r
+               $canlogin       = (integer) $canlogin;\r
+               $notes          = DB::quoteValue($notes);\r
+               \r
+               $query = "INSERT INTO %s"\r
+                      . " (MNAME,MREALNAME,MPASSWORD,MEMAIL,MURL, MADMIN, MCANLOGIN, MNOTES)"\r
+                      . " VALUES (%s, %s, %s, %s, %s, %d, %d, %s)";\r
+               $query = sprintf($query, sql_table('member'), $name, $realname, $password, $email, $url, $admin, $canlogin, $notes);\r
+               DB::execute($query);\r
+               \r
+               ActionLog::add(INFO, _ACTIONLOG_NEWMEMBER . ' ' . $name);\r
+               \r
+               return 1;\r
+       }\r
+       \r
+       /**\r
+        * Member::getActivationInfo()\r
+        * Returns activation info for a certain key (an object with properties vkey, vmember, ...)\r
+        * \r
+        * @static\r
+        * @param       string  $key    activation key\r
+        * @return      mixed   return 0 if failed, else return activation table object\r
+        * \r
+        */\r
+       public static function getActivationInfo($key)\r
+       {\r
+               $query = 'SELECT * FROM ' . sql_table('activation') . ' WHERE vkey=' . DB::quoteValue($key);\r
+               $res = DB::getResult($query);\r
+               \r
+               if ( !$res || ($res->rowCount() == 0) )\r
+               {\r
+                       return 0;\r
+               }\r
+               return $res->fetch();\r
+       }\r
+       \r
+       /**\r
+        * Member::generateActivationEntry()\r
+        * Creates an account activation key\r
+        * addresschange -> old email address\r
+        * \r
+        * @param       string  $type   one of the following values (determines what to do when activation expires)\r
+        *                              'register'      (new member registration)\r
+        *                              'forgot'        (forgotton password)\r
+        *                              'addresschange' (member address has changed)\r
+        * @param       string  $extra  extra info (needed when validation link expires)\r
+        * @return      string  activation key\r
+        */\r
+       public function generateActivationEntry($type, $extra = '')\r
+       {\r
+               // clean up old entries\r
+               $this->cleanupActivationTable();\r
+               \r
+               // kill any existing entries for the current member (delete is ok)\r
+               // (only one outstanding activation key can be present for a member)\r
+               DB::execute('DELETE FROM ' . sql_table('activation') . ' WHERE vmember=' . intval($this->getID()));\r
+               \r
+               // indicates if the member can log in while the link is active\r
+               $canLoginWhileActive = false;\r
+               switch ( $type )\r
+               {\r
+                       case 'forgot':\r
+                               $canLoginWhileActive = true;\r
+                               break;\r
+                       case 'register':\r
+                               break;\r
+                       case 'addresschange':\r
+                               $extra = $extra . '/' . ( $this->canLogin() ? '1' : '0' );\r
+                               break;\r
+               }\r
+               \r
+               $ok = false;\r
+               while ( !$ok )\r
+               {\r
+                       // generate a random key\r
+                       srand((double)microtime()*1000000);\r
+                       $key = $this->hash(uniqid(rand(), true));\r
+                       \r
+                       // attempt to add entry in database\r
+                       // add in database as non-active\r
+                       $query = 'INSERT INTO ' . sql_table('activation'). ' (vkey, vtime, vmember, vtype, vextra) ';\r
+                       $query .= 'VALUES (' . DB::quoteValue($key). ', \'' . date('Y-m-d H:i:s',time()) . '\', ' . intval($this->getID()). ', ' . DB::quoteValue($type). ', ' . DB::quoteValue($extra). ')';\r
+                       if ( DB::execute($query) !== FALSE )\r
+                               $ok = true;\r
+               }\r
+               \r
+               // mark member as not allowed to log in\r
+               if ( !$canLoginWhileActive )\r
+               {\r
+                       $this->setCanLogin(0);\r
+                       $this->write();\r
+               }\r
+               \r
+               // return the key\r
+               return $key;\r
+       }\r
+       \r
+       /**\r
+        * Member::activate()\r
+        * Inidicates that an activation link has been clicked and any forms displayed\r
+        * there have been successfully filled out.\r
+        * \r
+        * @param       string  $key    activation key\r
+        * @return      boolean\r
+        * \r
+        */\r
+       public function activate($key)\r
+       {\r
+               // get activate info\r
+               $info = self::getActivationInfo($key);\r
+               \r
+               // no active key\r
+               if ( !$info )\r
+               {\r
+                       return false;\r
+               }\r
+               \r
+               switch ( $info['vtype'] )\r
+               {\r
+                       case 'forgot':\r
+                               // nothing to do\r
+                               break;\r
+                       case 'register':\r
+                               // set canlogin value\r
+                               global $CONF;\r
+                               DB::execute('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($CONF['NewMemberCanLogon']). ' WHERE mnumber=' . intval($info['vmember']));\r
+                               break;\r
+                       case 'addresschange':\r
+                               // reset old 'canlogin' value\r
+                               list($oldEmail, $oldCanLogin) = preg_split('#/#', $info['vextra']);\r
+                               DB::execute('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($oldCanLogin). ' WHERE mnumber=' . intval($info['vmember']));\r
+                               break;\r
+               }\r
+               \r
+               // delete from activation table\r
+               DB::execute('DELETE FROM ' . sql_table('activation') . ' WHERE vkey=' . DB::quoteValue($key));\r
+               \r
+               // success!\r
+               return true;\r
+       }\r
+       \r
+       /**\r
+        * Member::cleanupActivationTable()\r
+        * Cleans up entries in the activation table. All entries older than 2 days are removed.\r
+        * (static)\r
+        * \r
+        * @param       void\r
+        * @return      void\r
+        */\r
+       public function cleanupActivationTable()\r
+       {\r
+               $actdays = 2;\r
+               if ( isset($CONF['ActivationDays']) && intval($CONF['ActivationDays']) > 0 )\r
+               {\r
+                       $actdays = intval($CONF['ActivationDays']);\r
+               }\r
+               else\r
+               {\r
+                       $CONF['ActivationDays'] = 2;\r
+               }\r
+               $boundary = time() - (60 * 60 * 24 * $actdays);\r
+               \r
+               // 1. walk over all entries, and see if special actions need to be performed\r
+               $res = DB::getResult('SELECT * FROM ' . sql_table('activation') . ' WHERE vtime < \'' . date('Y-m-d H:i:s',$boundary) . '\'');\r
+               \r
+               foreach ( $res as $row )\r
+               {\r
+                       switch ( $row['vtype'] )\r
+                       {\r
+                               case 'register':\r
+                                       // delete all information about this site member. registration is undone because there was\r
+                                       // no timely activation\r
+                                       include_once($DIR_LIBS . 'ADMIN.php');\r
+                                       Admin::deleteOneMember(intval($row['vmember']));\r
+                                       break;\r
+                               case 'addresschange':\r
+                                       // revert the e-mail address of the member back to old address\r
+                                       list($oldEmail, $oldCanLogin) = preg_split('#/#', $row['vextra']);\r
+                                       DB::execute('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($oldCanLogin). ', memail=' . DB::quoteValue($oldEmail). ' WHERE mnumber=' . intval($row['vmember']));\r
+                                       break;\r
+                               case 'forgot':\r
+                                       // delete the activation link and ignore. member can request a new password using the\r
+                                       // forgot password link\r
+                                       break;\r
+                       }\r
+               }\r
+               \r
+               // 2. delete activation entries for real\r
+               DB::execute('DELETE FROM ' . sql_table('activation') . ' WHERE vtime < \'' . date('Y-m-d H:i:s',$boundary) . '\'');\r
+               return;\r
+       }\r
+       \r
+       /**\r
+        * Member::$language\r
+        * \r
+        * @obsolete\r
+        * @param       void\r
+        * @return      void\r
+        * \r
+        */\r
+       public $language = '';\r
+       /**\r
+        * Member::getLanguage()\r
+        * \r
+        * @obsolete\r
+        * @param       void\r
+        * @return      void\r
+        * \r
+        */\r
+       public function getLanguage()\r
+       {\r
+               if ( ($language = i18n::convert_locale_to_old_language_file_name($this->locale)) === FALSE )\r
+               {\r
+                       $language = '';\r
+               }\r
+               return $language;\r
+       }\r
+}\r