<?php
#
# Copyright 2003 James Seng. See LICENSE for the Software License.
#

$GLOBALS['conf_ffriends'] = "friends";

function friends_element_start($parser,$name,$attribs) {
    if (!isset($GLOBALS['friends_load'])) return 0;
    if ($name == "OUTLINE") {
        $username = $attribs['TEXT'];
        $userid = $attribs['USERID'];
        $passwd = $attribs['PASSWD'];
        $acl = explode(":",$attribs['ACL']);
        if (isset($userid) && $userid != '')
            $GLOBALS['friends_load']->add_friend($userid,$username,
                $passwd,$acl);
    }
}

function friends_element_end($parser,$name) {
}

class func_friends extends function_base {
    var $friends = array();

    function func_friends() {
        $this->load($GLOBALS['conf_ffriends']);
        $GLOBALS['friends'] =& $this;

        // there is always a default friend...can not be deleted
        if (!isset($this->friends['default'])) 
            $this->add_friend('default','Default','',array());
    }

    function print_menu($type) {
        if ($type == 'short') {
            print "<a href=\"?q=show_friends\">Friends</a> | ";
            return;
        }

        if ($type == 'long') {
            print <<<_LONG_
<tr>
  <td align="right" width="25%" valign="top">
    <a href="?q=show_friends">Edit Friends</a></td>
  <td align="left" width="75%" valign="top">
    This is the "PonG server". You can define friends who 
    can access your portfolio. You can also customize what attributes
    they can access individually. For example, some friends may have 
    access to your business email address while others may have access 
    to your personal email address.
    </td>
  </tr>
_LONG_;
        }
    }

    function add_friend($userid,$name,$passwd,$acl) {
        if (!isset($this->friends[$userid])) {
            $this->friends[$userid] = array("name" => $name,
                                            "passwd" => $passwd,
                                            "acl" => $acl);
        }
    }

    function del_friend($userid) {
        if ($userid == 'default') return;
        if (isset($this->friends[$userid]))
            unset($this->friends[$userid]);
    }

    function load($file = "friends") {
        $filename = $this->filename($file);

        $GLOBALS['friends_load'] =& $this;

        if (!file_exists($filename))
            return 0;

        if (!($fh = fopen($filename,"r")))
            return $this->error("Unable to open $filename for reading.");

        $xml_parser = xml_parser_create();
        xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING,1);
        xml_set_element_handler($xml_parser, "friends_element_start",
            "friends_element_end");

        while ($data = fread($fh, 4096)) {
            if (!xml_parse($xml_parser,$data,feof($fh))) 
                return $this->error(sprintf(
                    "%s: XML parse error %s at line %d.",
                        $filename,
                        xml_error_string(xml_get_error_code($xml_parser)),
                        xml_get_current_line_number($xml_parser)));
        }

        xml_parser_free($xml_parser);

        unset($GLOBALS['friends_load']);

        return 1;
    }

    function save($file = "friends") {
        global $config;

        ignore_user_abort(true);
    
        if (!isset($config->conf['datecreated'])) {
            $config->set('datecreated',long_datetime());
        }
    
        $filename = $this->tempfile($file);
    
        if (!($fh = fopen($filename, 'w')))
            return $this->error("Unable to open $filename for writing.");
    
        if (flock($fh,LOCK_EX | LOCK_NB)) {
            fwrite($fh,$this->opml_header("Pong Friends"));
            foreach ($this->friends as $userid => $friend) {
                $name = htmlspecialchars($friend['name']);
                $passwd = htmlspecialchars($friend['passwd']);
                $acl = htmlspecialchars(implode(":",$friend['acl']));
                $str = <<<_FRIEND_
    <outline text="$name" userid="$userid" passwd="$passwd" acl="$acl">

_FRIEND_;
                fwrite($fh,$str);
            }
            fwrite($fh,$this->opml_footer());
            flock($fh,LOCK_UN);
        }
        fclose($fh);
    
        copy($filename,$this->filename($file));
        unlink($filename);
    
        ignore_user_abort(false);
    
        return 1;
    }

    function show_form() {
        print <<<_FORM_HEAD_
<center>
<form method="POST" action="?q=update_friends">
<table class="table" cellpadding="5" width="50%">
<tr>
  <td class="title" colspan="3" align="center">
    Friends Info</td>
  </tr>
_FORM_HEAD_;

        foreach ($this->friends as $userid => $friend) {
            unset($disabled);
            if ($userid != 'default' && $friend['passwd'] == '') {
                $disabled = "(<i>No password - <b>Disabled</b></i>)";
            }

            print <<<_FRIEND_
<tr>
  <td valign="middle" width="5%">
    <input type="checkbox" name="_$userid">
  <td valign="middle" width="25%" align="left">
    <a href="?q=show_friend&userid=$userid">$userid</a>
    </td>
  <td valign="middle" width="70%" align="left">
    ${friend['name']} $disabled
    </td>
  </tr>
_FRIEND_;
        }

        print <<<_FORM_TAIL_
<tr>
  <td colspan="3" align="center">
    <input name=_add size="12">
    <input class=button type=submit name=submit value=add> &nbsp;
    <input class=button type=submit name=submit value=delete> &nbsp; 
    </td>
  </tr>
<tr>
  <td class="help" colspan="3" align="left">
    To add friends who can access your profile, enter an userid for your
    friend and click "Add". To remove them, check on the boxes on the left
    and click "Delete". To modify the access control for your friend, click
    on their userid.
    <p>
    The "default" is the access control for general public.
    </td>
  </tr>
</table>
</form>
</center>

_FORM_TAIL_;
        return 1;
}

    function show_friend($userid) {
        global $profile;

        if (!isset($this->friends[$userid])) {
            showmsg("error","No such userid : $userid.");
            return $this->show_form();
        }
        $friend =& $this->friends[$userid];

        if ($userid != 'default' && $friend['passwd'] == '') {
            $disabled = "(<i>No password - Disabled</i>)";
        }

        print <<<_FORM_HEAD_
<center>
<form method="POST" action="?q=update_friend&userid=$userid">
<table class="table" cellpadding="5" width="60%">
<tr>
  <td class="title" colspan="2" align="center">
     $userid $disabled</td>
  </tr>
_FORM_HEAD_;

        print <<<_FRIENDNAME_
<tr>
  <td valign="middle" width="30%" align="left">
    Name of your friend</td>
  <td valign="middle" width="70%" align="left">
    <font class="title">Name</font><br>
    <input class="text" name="name" value="${friend['name']}">
    </td>
  </tr>
_FRIENDNAME_;

        if (has_module("func_profile") && isset($profile->attribs)) {
            print <<<_ACLHEAD_
<tr>
  <td class="subtitle" colspan="2">
  Access Control</td>
  </tr>

_ACLHEAD_;

            foreach ($profile->attribs as $att => $v) {
                $attrib =& $profile->attribs[$att];
                $class = get_class($attrib);
                $data = $attrib->get();
                $id = $attrib->getid();

                foreach ($friend['acl'] as $v) {
                    $on[$v] = "checked";
                }

                print <<<_ATTRIB_
<tr>
  <td valign="middle" width="30%" align="left">
    <input type="checkbox" name="_$id" ${on[$id]}> &nbsp; $class
    </td>
  <td valign="middle" width="70%" align="left">
    $data
    </td>
  </tr>
_ATTRIB_;
            }
        }

        print <<<_FORM_TAIL_
<tr>
  <td valign="middle" align="left">
    <input class=button type=submit name=submit value=save> &nbsp; 
    </td>
  <td valign="middle" align="right">
    <font class="title">Password Reset</font> 
    <input type=password name=_passwd size="12">
    <input class=button type=submit name=submit value=reset> &nbsp;
    </td>
  </tr>
<tr>
  <td class="help" colspan="2" align="left">
    Check on the boxes on the left to define the information you allow
    this friend to access. (If this is default, then you are defining
    the access control for the general public.) Click on "Save" when done.
    <p>
    You can change the password for this friend by entering the password
    and click "Reset". If you select an empty password, then the account
    will be disabled.
    </td>
  </tr>
</table>
</form>
</center>

_FORM_TAIL_;
        return 1;
    }

    function config() {
        return array("autoadd" => "Auto Add People who PonG'ed me (yes or no)");
    }

    function xmlrpc() {
        return array(
            "pong.getContact" => array("function" => "pong_getContact"));
    }
}

function cmd_show_friends() {
    global $friends;
    return $friends->show_form();
}

function cmd_update_friends() {
    global $friends;

    if ($_REQUEST['submit'] == 'delete') {
        foreach ($friends->friends as $friend => $v) {
            if ($_REQUEST["_".$friend] == "on") 
                $friends->del_friend($friend);
        }
        showmsg("ok","Successfully deleted checked friends.");
        $friends->save();
    } else if ($_REQUEST['submit'] == 'add') {
        $userid = $_REQUEST['_add'];
        if (!preg_match("/^[a-zA-Z0-9]+$/",$userid))
            showmsg("error","Userid must be alphanumeric only.");
        else if (isset($friends->friends[$userid]))
            showmsg("error","$userid already exists.");
        else {
            $friends->add_friend($userid,"","",array());
            $friends->save();
        }
    } else {
        showmsg("error","Unknown request ${_REQUEST['submit']}");
    }

    return $friends->show_form();
}

function cmd_show_friend() {
    global $friends;

    $userid = $_REQUEST['userid'];
    return $friends->show_friend($userid);
}

function cmd_update_friend() {
    global $friends, $profile;

    $userid = $_REQUEST['userid'];
    $friend =& $friends->friends[$userid];

    if (!isset($friend)) {
        showmsg("error","No such userid : $userid.");
        return $friends->show_form();
    } else if ($_REQUEST['submit'] == 'save') {
        $friend['name'] = $_REQUEST['name'];
        if (has_module("func_profile") && isset($profile->attribs)) {
            $acl = array();
            foreach ($profile->attribs as $att => $v) {
                $id = $profile->attribs[$att]->getid();
                if ($_REQUEST["_".$id] == "on")
                    $acl = array_merge($acl,$id);
            }
            $friend['acl'] = $acl;
        }
        $friends->save();
        showmsg("ok","$userid info saved.");
    } else if ($_REQUEST['submit'] == 'reset') {
        if ($userid == 'default') {
            showmsg("error","You cannot change the password for default.");
        } else {
            if ($_REQUEST['_passwd'] == '')
                $friend['passwd'] = '';
            else
                $friend['passwd'] = crypt($_REQUEST['_passwd']);
            showmsg("ok","$userid password reset.");
            $friends->save();
        }
    } else {
        showmsg("error","Unknown request ${_REQUEST['submit']}");
    }

    return $friends->show_friend($userid);
}

function pong_getContact($params) {
    global $profile, $friends, $config;

    $resp = array();

    if (!isset($profile->attribs)) return new xmlrpcval(array(),"array");

    $cparams = params_convert($params);
    $userid = $cparams[0];
    $passwd = $cparams[1];
    $purl = $cparams[2];

    if (!isset($friends->friends[$userid])
    ||   $friends->friends[$userid]['passwd'] == '') {
        $userid = "default";
    } 

    if ($userid != 'default') {
        if (crypt($passwd,$friends->friends[$userid]['passwd']) !=
            $friends->friends[$userid]['passwd']) {
            $userid = "default";
        }
    }

    $friend =& $friends->friends[$userid];
    $acl = $friend['acl'];

    if (has_module("func_profile") && isset($profile->attribs)) {
        foreach ($profile->attribs as $att => $v) {
            if (!in_array($profile->attribs[$att]->getid(),$acl)) continue;
            $resp[] = $profile->attribs[$att]->module_invoke(
                "attrib_base","xmlrpc_profile");
        }
    }

    if (isset($purl) && preg_match("/^http/",$purl)
    &&  strtolower($config->get('autoadd')) == 'yes'
    &&  has_module("func_contacts")) {
        global $contacts;

        $found = 0;
        foreach ($contacts->contacts as $contact) {
            if ($contact['url'] == $purl) $found = 1;
        }
        if (!$found) {
            $id = count($contacts->contacts);
            $contacts->add_contact($id,$config->get('userid'),'',$purl);
            $contacts->save();
        }
    }

    return new xmlrpcresp(new xmlrpcval($resp,"array"));
}

?>
