Example #1
1
function create_user($arr)
{
    // Required: { username, nickname, email } or { openid_url }
    $a = get_app();
    $result = array('success' => false, 'user' => null, 'password' => '', 'message' => '');
    $using_invites = get_config('system', 'invitation_only');
    $num_invites = get_config('system', 'number_invites');
    $invite_id = x($arr, 'invite_id') ? notags(trim($arr['invite_id'])) : '';
    $username = x($arr, 'username') ? notags(trim($arr['username'])) : '';
    $nickname = x($arr, 'nickname') ? notags(trim($arr['nickname'])) : '';
    $email = x($arr, 'email') ? notags(trim($arr['email'])) : '';
    $openid_url = x($arr, 'openid_url') ? notags(trim($arr['openid_url'])) : '';
    $photo = x($arr, 'photo') ? notags(trim($arr['photo'])) : '';
    $password = x($arr, 'password') ? trim($arr['password']) : '';
    $blocked = x($arr, 'blocked') ? intval($arr['blocked']) : 0;
    $verified = x($arr, 'verified') ? intval($arr['verified']) : 0;
    $publish = x($arr, 'profile_publish_reg') && intval($arr['profile_publish_reg']) ? 1 : 0;
    $netpublish = strlen(get_config('system', 'directory_submit_url')) ? $publish : 0;
    $tmp_str = $openid_url;
    if ($using_invites) {
        if (!$invite_id) {
            $result['message'] .= t('An invitation is required.') . EOL;
            return $result;
        }
        $r = q("select * from register where `hash` = '%s' limit 1", dbesc($invite_id));
        if (!results($r)) {
            $result['message'] .= t('Invitation could not be verified.') . EOL;
            return $result;
        }
    }
    if (!x($username) || !x($email) || !x($nickname)) {
        if ($openid_url) {
            if (!validate_url($tmp_str)) {
                $result['message'] .= t('Invalid OpenID url') . EOL;
                return $result;
            }
            $_SESSION['register'] = 1;
            $_SESSION['openid'] = $openid_url;
            require_once 'library/openid.php';
            $openid = new LightOpenID();
            $openid->identity = $openid_url;
            $openid->returnUrl = $a->get_baseurl() . '/openid';
            $openid->required = array('namePerson/friendly', 'contact/email', 'namePerson');
            $openid->optional = array('namePerson/first', 'media/image/aspect11', 'media/image/default');
            try {
                $authurl = $openid->authUrl();
            } catch (Exception $e) {
                $result['message'] .= t("We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID.") . EOL . EOL . t("The error message was:") . $e->getMessage() . EOL;
                return $result;
            }
            goaway($authurl);
            // NOTREACHED
        }
        notice(t('Please enter the required information.') . EOL);
        return;
    }
    if (!validate_url($tmp_str)) {
        $openid_url = '';
    }
    $err = '';
    // collapse multiple spaces in name
    $username = preg_replace('/ +/', ' ', $username);
    if (mb_strlen($username) > 48) {
        $result['message'] .= t('Please use a shorter name.') . EOL;
    }
    if (mb_strlen($username) < 3) {
        $result['message'] .= t('Name too short.') . EOL;
    }
    // I don't really like having this rule, but it cuts down
    // on the number of auto-registrations by Russian spammers
    //  Using preg_match was completely unreliable, due to mixed UTF-8 regex support
    //	$no_utf = get_config('system','no_utf');
    //	$pat = (($no_utf) ? '/^[a-zA-Z]* [a-zA-Z]*$/' : '/^\p{L}* \p{L}*$/u' );
    // So now we are just looking for a space in the full name.
    $loose_reg = get_config('system', 'no_regfullname');
    if (!$loose_reg) {
        $username = mb_convert_case($username, MB_CASE_TITLE, 'UTF-8');
        if (!strpos($username, ' ')) {
            $result['message'] .= t("That doesn't appear to be your full (First Last) name.") . EOL;
        }
    }
    if (!allowed_email($email)) {
        $result['message'] .= t('Your email domain is not among those allowed on this site.') . EOL;
    }
    if (!valid_email($email) || !validate_email($email)) {
        $result['message'] .= t('Not a valid email address.') . EOL;
    }
    // Disallow somebody creating an account using openid that uses the admin email address,
    // since openid bypasses email verification. We'll allow it if there is not yet an admin account.
    $adminlist = explode(",", str_replace(" ", "", strtolower($a->config['admin_email'])));
    //if((x($a->config,'admin_email')) && (strcasecmp($email,$a->config['admin_email']) == 0) && strlen($openid_url)) {
    if (x($a->config, 'admin_email') && in_array(strtolower($email), $adminlist) && strlen($openid_url)) {
        $r = q("SELECT * FROM `user` WHERE `email` = '%s' LIMIT 1", dbesc($email));
        if (count($r)) {
            $result['message'] .= t('Cannot use that email.') . EOL;
        }
    }
    $nickname = $arr['nickname'] = strtolower($nickname);
    if (!preg_match("/^[a-z][a-z0-9\\-\\_]*\$/", $nickname)) {
        $result['message'] .= t('Your "nickname" can only contain "a-z", "0-9", "-", and "_", and must also begin with a letter.') . EOL;
    }
    $r = q("SELECT `uid` FROM `user`\n               \tWHERE `nickname` = '%s' LIMIT 1", dbesc($nickname));
    if (count($r)) {
        $result['message'] .= t('Nickname is already registered. Please choose another.') . EOL;
    }
    // Check deleted accounts that had this nickname. Doesn't matter to us,
    // but could be a security issue for federated platforms.
    $r = q("SELECT * FROM `userd`\n               \tWHERE `username` = '%s' LIMIT 1", dbesc($nickname));
    if (count($r)) {
        $result['message'] .= t('Nickname was once registered here and may not be re-used. Please choose another.') . EOL;
    }
    if (strlen($result['message'])) {
        return $result;
    }
    $new_password = strlen($password) ? $password : autoname(6) . mt_rand(100, 9999);
    $new_password_encoded = hash('whirlpool', $new_password);
    $result['password'] = $new_password;
    require_once 'include/crypto.php';
    $keys = new_keypair(4096);
    if ($keys === false) {
        $result['message'] .= t('SERIOUS ERROR: Generation of security keys failed.') . EOL;
        return $result;
    }
    $default_service_class = get_config('system', 'default_service_class');
    if (!$default_service_class) {
        $default_service_class = '';
    }
    $prvkey = $keys['prvkey'];
    $pubkey = $keys['pubkey'];
    /**
     *
     * Create another keypair for signing/verifying
     * salmon protocol messages. We have to use a slightly
     * less robust key because this won't be using openssl
     * but the phpseclib. Since it is PHP interpreted code
     * it is not nearly as efficient, and the larger keys
     * will take several minutes each to process.
     *
     */
    $sres = new_keypair(512);
    $sprvkey = $sres['prvkey'];
    $spubkey = $sres['pubkey'];
    $r = q("INSERT INTO `user` ( `guid`, `username`, `password`, `email`, `openid`, `nickname`,\n\t\t`pubkey`, `prvkey`, `spubkey`, `sprvkey`, `register_date`, `verified`, `blocked`, `timezone`, `service_class`, `default-location` )\n\t\tVALUES ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, 'UTC', '%s', '' )", dbesc(generate_user_guid()), dbesc($username), dbesc($new_password_encoded), dbesc($email), dbesc($openid_url), dbesc($nickname), dbesc($pubkey), dbesc($prvkey), dbesc($spubkey), dbesc($sprvkey), dbesc(datetime_convert()), intval($verified), intval($blocked), dbesc($default_service_class));
    if ($r) {
        $r = q("SELECT * FROM `user`\n\t\t\tWHERE `username` = '%s' AND `password` = '%s' LIMIT 1", dbesc($username), dbesc($new_password_encoded));
        if ($r !== false && count($r)) {
            $u = $r[0];
            $newuid = intval($r[0]['uid']);
        }
    } else {
        $result['message'] .= t('An error occurred during registration. Please try again.') . EOL;
        return $result;
    }
    /**
     * if somebody clicked submit twice very quickly, they could end up with two accounts
     * due to race condition. Remove this one.
     */
    $r = q("SELECT `uid` FROM `user`\n               \tWHERE `nickname` = '%s' ", dbesc($nickname));
    if (count($r) > 1 && $newuid) {
        $result['message'] .= t('Nickname is already registered. Please choose another.') . EOL;
        q("DELETE FROM `user` WHERE `uid` = %d", intval($newuid));
        return $result;
    }
    if (x($newuid) !== false) {
        $r = q("INSERT INTO `profile` ( `uid`, `profile-name`, `is-default`, `name`, `photo`, `thumb`, `publish`, `net-publish` )\n\t\t\tVALUES ( %d, '%s', %d, '%s', '%s', '%s', %d, %d ) ", intval($newuid), t('default'), 1, dbesc($username), dbesc($a->get_baseurl() . "/photo/profile/{$newuid}.jpg"), dbesc($a->get_baseurl() . "/photo/avatar/{$newuid}.jpg"), intval($publish), intval($netpublish));
        if ($r === false) {
            $result['message'] .= t('An error occurred creating your default profile. Please try again.') . EOL;
            // Start fresh next time.
            $r = q("DELETE FROM `user` WHERE `uid` = %d", intval($newuid));
            return $result;
        }
        $r = q("INSERT INTO `contact` ( `uid`, `created`, `self`, `name`, `nick`, `photo`, `thumb`, `micro`, `blocked`, `pending`, `url`, `nurl`,\n\t\t\t`request`, `notify`, `poll`, `confirm`, `poco`, `name-date`, `uri-date`, `avatar-date`, `closeness` )\n\t\t\tVALUES ( %d, '%s', 1, '%s', '%s', '%s', '%s', '%s', 0, 0, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', 0 ) ", intval($newuid), datetime_convert(), dbesc($username), dbesc($nickname), dbesc($a->get_baseurl() . "/photo/profile/{$newuid}.jpg"), dbesc($a->get_baseurl() . "/photo/avatar/{$newuid}.jpg"), dbesc($a->get_baseurl() . "/photo/micro/{$newuid}.jpg"), dbesc($a->get_baseurl() . "/profile/{$nickname}"), dbesc(normalise_link($a->get_baseurl() . "/profile/{$nickname}")), dbesc($a->get_baseurl() . "/dfrn_request/{$nickname}"), dbesc($a->get_baseurl() . "/dfrn_notify/{$nickname}"), dbesc($a->get_baseurl() . "/dfrn_poll/{$nickname}"), dbesc($a->get_baseurl() . "/dfrn_confirm/{$nickname}"), dbesc($a->get_baseurl() . "/poco/{$nickname}"), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert()));
        // Create a group with no members. This allows somebody to use it
        // right away as a default group for new contacts.
        require_once 'include/group.php';
        group_add($newuid, t('Friends'));
        $r = q("SELECT id FROM `group` WHERE uid = %d AND name = '%s'", intval($newuid), dbesc(t('Friends')));
        if ($r && count($r)) {
            $def_gid = $r[0]['id'];
            q("UPDATE user SET def_gid = %d WHERE uid = %d", intval($r[0]['id']), intval($newuid));
        }
        if (get_config('system', 'newuser_private') && $def_gid) {
            q("UPDATE user SET allow_gid = '%s' WHERE uid = %d", dbesc("<" . $def_gid . ">"), intval($newuid));
        }
    }
    // if we have no OpenID photo try to look up an avatar
    if (!strlen($photo)) {
        $photo = avatar_img($email);
    }
    // unless there is no avatar-plugin loaded
    if (strlen($photo)) {
        require_once 'include/Photo.php';
        $photo_failure = false;
        $filename = basename($photo);
        $img_str = fetch_url($photo, true);
        // guess mimetype from headers or filename
        $type = guess_image_type($photo, true);
        $img = new Photo($img_str, $type);
        if ($img->is_valid()) {
            $img->scaleImageSquare(175);
            $hash = photo_new_resource();
            $r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 4);
            if ($r === false) {
                $photo_failure = true;
            }
            $img->scaleImage(80);
            $r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 5);
            if ($r === false) {
                $photo_failure = true;
            }
            $img->scaleImage(48);
            $r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 6);
            if ($r === false) {
                $photo_failure = true;
            }
            if (!$photo_failure) {
                q("UPDATE `photo` SET `profile` = 1 WHERE `resource-id` = '%s' ", dbesc($hash));
            }
        }
    }
    call_hooks('register_account', $newuid);
    $result['success'] = true;
    $result['user'] = $u;
    return $result;
}
Example #2
0
function photo_init(&$a)
{
    global $_SERVER;
    $prvcachecontrol = false;
    $file = "";
    switch ($a->argc) {
        case 4:
            $person = $a->argv[3];
            $customres = intval($a->argv[2]);
            $type = $a->argv[1];
            break;
        case 3:
            $person = $a->argv[2];
            $type = $a->argv[1];
            break;
        case 2:
            $photo = $a->argv[1];
            $file = $photo;
            break;
        case 1:
        default:
            killme();
            // NOTREACHED
    }
    //	strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= filemtime($localFileName)) {
    if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
        header('HTTP/1.1 304 Not Modified');
        header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT");
        header('Etag: ' . $_SERVER['HTTP_IF_NONE_MATCH']);
        header("Expires: " . gmdate("D, d M Y H:i:s", time() + 31536000) . " GMT");
        header("Cache-Control: max-age=31536000");
        if (function_exists('header_remove')) {
            header_remove('Last-Modified');
            header_remove('Expires');
            header_remove('Cache-Control');
        }
        exit;
    }
    $default = 'images/person-175.jpg';
    if (isset($type)) {
        /**
         * Profile photos
         */
        switch ($type) {
            case 'profile':
            case 'custom':
                $resolution = 4;
                break;
            case 'micro':
                $resolution = 6;
                $default = 'images/person-48.jpg';
                break;
            case 'avatar':
            default:
                $resolution = 5;
                $default = 'images/person-80.jpg';
                break;
        }
        $uid = str_replace(array('.jpg', '.png'), array('', ''), $person);
        $r = q("SELECT * FROM `photo` WHERE `scale` = %d AND `uid` = %d AND `profile` = 1 LIMIT 1", intval($resolution), intval($uid));
        if (count($r)) {
            $data = $r[0]['data'];
            $mimetype = $r[0]['type'];
        }
        if (!isset($data)) {
            $data = file_get_contents($default);
            $mimetype = 'image/jpeg';
        }
    } else {
        /**
         * Other photos
         */
        $resolution = 0;
        foreach (Photo::supportedTypes() as $m => $e) {
            $photo = str_replace(".{$e}", '', $photo);
        }
        if (substr($photo, -2, 1) == '-') {
            $resolution = intval(substr($photo, -1, 1));
            $photo = substr($photo, 0, -2);
        }
        // check if the photo exists and get the owner of the photo
        $r = q("SELECT `uid` FROM `photo` WHERE `resource-id` = '%s' LIMIT 1", dbesc($photo), intval($resolution));
        if (count($r)) {
            $sql_extra = permissions_sql($r[0]['uid']);
            // Now we'll see if we can access the photo
            $r = q("SELECT * FROM `photo` WHERE `resource-id` = '%s' AND `scale` <= %d {$sql_extra} ORDER BY scale DESC LIMIT 1", dbesc($photo), intval($resolution));
            $public = $r[0]['allow_cid'] == '' and $r[0]['allow_gid'] == '' and $r[0]['deny_cid'] == '' and $r[0]['deny_gid'] == '';
            if (count($r)) {
                $resolution = $r[0]['scale'];
                $data = $r[0]['data'];
                $mimetype = $r[0]['type'];
            } else {
                // The picure exists. We already checked with the first query.
                // obviously, this is not an authorized viev!
                $data = file_get_contents('images/nosign.jpg');
                $mimetype = 'image/jpeg';
                $prvcachecontrol = true;
                $public = false;
            }
        }
    }
    if (!isset($data)) {
        if (isset($resolution)) {
            switch ($resolution) {
                case 4:
                    $data = file_get_contents('images/person-175.jpg');
                    $mimetype = 'image/jpeg';
                    break;
                case 5:
                    $data = file_get_contents('images/person-80.jpg');
                    $mimetype = 'image/jpeg';
                    break;
                case 6:
                    $data = file_get_contents('images/person-48.jpg');
                    $mimetype = 'image/jpeg';
                    break;
                default:
                    killme();
                    // NOTREACHED
                    break;
            }
        }
    }
    // Resize only if its not a GIF
    if ($mime != "image/gif") {
        $ph = new Photo($data, $mimetype);
        if ($ph->is_valid()) {
            if (isset($customres) && $customres > 0 && $customres < 500) {
                $ph->scaleImageSquare($customres);
            }
            $data = $ph->imageString();
            $mimetype = $ph->getType();
        }
    }
    if (function_exists('header_remove')) {
        header_remove('Pragma');
        header_remove('pragma');
    }
    header("Content-type: " . $mimetype);
    if ($prvcachecontrol) {
        // it is a private photo that they have no permission to view.
        // tell the browser not to cache it, in case they authenticate
        // and subsequently have permission to see it
        header("Cache-Control: no-store, no-cache, must-revalidate");
    } else {
        header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT");
        header('Etag: "' . md5($data) . '"');
        header("Expires: " . gmdate("D, d M Y H:i:s", time() + 31536000) . " GMT");
        header("Cache-Control: max-age=31536000");
    }
    echo $data;
    // If the photo is public and there is an existing photo directory store the photo there
    if ($public and $file != "") {
        // If the photo path isn't there, try to create it
        $basepath = $a->get_basepath();
        if (!is_dir($basepath . "/photo")) {
            if (is_writable($basepath)) {
                mkdir($basepath . "/photo");
            }
        }
        if (is_dir($basepath . "/photo")) {
            file_put_contents($basepath . "/photo/" . $file, $data);
        }
    }
    killme();
    // NOTREACHED
}
Example #3
0
     if ($photo_rawupdate) {
         $photo_timestamp = datetime_convert('UTC', 'UTC', $photo_rawupdate[0]['data']);
         $photo_url = $feed->get_image_url();
     }
 }
 if ($photo_timestamp && strlen($photo_url) && $photo_timestamp > $contact['avatar-date']) {
     require_once "Photo.php";
     $photo_failure = false;
     $r = q("SELECT `resource-id` FROM `photo` WHERE `contact-id` = %d LIMIT 1", intval($contact['id']));
     if (count($r)) {
         $resource_id = $r[0]['resource-id'];
         $img_str = fetch_url($photo_url, true);
         $img = new Photo($img_str);
         if ($img) {
             q("DELETE FROM `photo` WHERE `resource-id` = '%s' AND contact-id` = %d ", dbesc($resource_id), intval($contact['id']));
             $img->scaleImageSquare(175);
             $hash = $resource_id;
             $r = $img->store($contact['id'], $hash, basename($photo_url), t('Contact Photos'), 4);
             $img->scaleImage(80);
             $r = $img->store($contact['id'], $hash, basename($photo_url), t('Contact Photos'), 5);
             if ($r) {
                 q("UPDATE `contact` SET `avatar-date` = '%s' WHERE `id` = %d LIMIT 1", dbesc(datetime_convert()), intval($contact['id']));
             }
         }
     }
 }
 if ($name_updated && strlen($new_name) && $name_updated > $contact['name-date']) {
     q("UPDATE `contact` SET `name` = '%s', `name-date` = '%s' WHERE `id` = %d LIMIT 1", dbesc(notags(trim($new_name))), dbesc(datetime_convert()), intval($contact['id']));
 }
 // Now process the feed
 foreach ($feed->get_items() as $item) {
Example #4
0
 function register_post(&$a)
 {
     global $lang;
     $verified = 0;
     $blocked = 1;
     switch ($a->config['register_policy']) {
         case REGISTER_OPEN:
             $blocked = 0;
             $verified = 1;
             break;
         case REGISTER_APPROVE:
             $blocked = 1;
             $verified = 0;
             break;
         default:
         case REGISTER_CLOSED:
             if (!x($_SESSION, 'authenticated') && !x($_SESSION, 'administrator')) {
                 notice(t('Permission denied.') . EOL);
                 return;
             }
             $blocked = 1;
             $verified = 0;
             break;
     }
     $using_invites = get_config('system', 'invitation_only');
     $num_invites = get_config('system', 'number_invites');
     $invite_id = x($_POST, 'invite_id') ? notags(trim($_POST['invite_id'])) : '';
     $username = x($_POST, 'username') ? notags(trim($_POST['username'])) : '';
     $nickname = x($_POST, 'nickname') ? notags(trim($_POST['nickname'])) : '';
     $email = x($_POST, 'email') ? notags(trim($_POST['email'])) : '';
     $openid_url = x($_POST, 'openid_url') ? notags(trim($_POST['openid_url'])) : '';
     $photo = x($_POST, 'photo') ? notags(trim($_POST['photo'])) : '';
     $publish = x($_POST, 'profile_publish_reg') && intval($_POST['profile_publish_reg']) ? 1 : 0;
     $netpublish = strlen(get_config('system', 'directory_submit_url')) ? $publish : 0;
     $tmp_str = $openid_url;
     if ($using_invites) {
         if (!$invite_id) {
             notice(t('An invitation is required.') . EOL);
             return;
         }
         $r = q("select * from register where `hash` = '%s' limit 1", dbesc($invite_id));
         if (!results($r)) {
             notice(t('Invitation could not be verified.') . EOL);
             return;
         }
     }
     if (!x($username) || !x($email) || !x($nickname)) {
         if ($openid_url) {
             if (!validate_url($tmp_str)) {
                 notice(t('Invalid OpenID url') . EOL);
                 return;
             }
             $_SESSION['register'] = 1;
             $_SESSION['openid'] = $openid_url;
             require_once 'library/openid.php';
             $openid = new LightOpenID();
             $openid->identity = $openid_url;
             $openid->returnUrl = $a->get_baseurl() . '/openid';
             $openid->required = array('namePerson/friendly', 'contact/email', 'namePerson');
             $openid->optional = array('namePerson/first', 'media/image/aspect11', 'media/image/default');
             goaway($openid->authUrl());
             // NOTREACHED
         }
         notice(t('Please enter the required information.') . EOL);
         return;
     }
     if (!validate_url($tmp_str)) {
         $openid_url = '';
     }
     $err = '';
     // collapse multiple spaces in name
     $username = preg_replace('/ +/', ' ', $username);
     if (mb_strlen($username) > 48) {
         $err .= t('Please use a shorter name.') . EOL;
     }
     if (mb_strlen($username) < 3) {
         $err .= t('Name too short.') . EOL;
     }
     // I don't really like having this rule, but it cuts down
     // on the number of auto-registrations by Russian spammers
     //  Using preg_match was completely unreliable, due to mixed UTF-8 regex support
     //	$no_utf = get_config('system','no_utf');
     //	$pat = (($no_utf) ? '/^[a-zA-Z]* [a-zA-Z]*$/' : '/^\p{L}* \p{L}*$/u' );
     // So now we are just looking for a space in the full name.
     $loose_reg = get_config('system', 'no_regfullname');
     if (!$loose_reg) {
         $username = mb_convert_case($username, MB_CASE_TITLE, 'UTF-8');
         if (!strpos($username, ' ')) {
             $err .= t("That doesn't appear to be your full (First Last) name.") . EOL;
         }
     }
     if (!allowed_email($email)) {
         $err .= t('Your email domain is not among those allowed on this site.') . EOL;
     }
     if (!valid_email($email) || !validate_email($email)) {
         $err .= t('Not a valid email address.') . EOL;
     }
     // Disallow somebody creating an account using openid that uses the admin email address,
     // since openid bypasses email verification. We'll allow it if there is not yet an admin account.
     if (x($a->config, 'admin_email') && strcasecmp($email, $a->config['admin_email']) == 0 && strlen($openid_url)) {
         $r = q("SELECT * FROM `user` WHERE `email` = '%s' LIMIT 1", dbesc($email));
         if (count($r)) {
             $err .= t('Cannot use that email.') . EOL;
         }
     }
     $nickname = $_POST['nickname'] = strtolower($nickname);
     if (!preg_match("/^[a-z][a-z0-9\\-\\_]*\$/", $nickname)) {
         $err .= t('Your "nickname" can only contain "a-z", "0-9", "-", and "_", and must also begin with a letter.') . EOL;
     }
     $r = q("SELECT `uid` FROM `user`\n               \tWHERE `nickname` = '%s' LIMIT 1", dbesc($nickname));
     if (count($r)) {
         $err .= t('Nickname is already registered. Please choose another.') . EOL;
     }
     if (strlen($err)) {
         notice($err);
         return;
     }
     $new_password = autoname(6) . mt_rand(100, 9999);
     $new_password_encoded = hash('whirlpool', $new_password);
     $res = openssl_pkey_new(array('digest_alg' => 'sha1', 'private_key_bits' => 4096, 'encrypt_key' => false));
     // Get private key
     if (empty($res)) {
         notice(t('SERIOUS ERROR: Generation of security keys failed.') . EOL);
         return;
     }
     $prvkey = '';
     openssl_pkey_export($res, $prvkey);
     // Get public key
     $pkey = openssl_pkey_get_details($res);
     $pubkey = $pkey["key"];
     /**
      *
      * Create another keypair for signing/verifying
      * salmon protocol messages. We have to use a slightly
      * less robust key because this won't be using openssl
      * but the phpseclib. Since it is PHP interpreted code
      * it is not nearly as efficient, and the larger keys
      * will take several minutes each to process.
      *
      */
     $sres = openssl_pkey_new(array('digest_alg' => 'sha1', 'private_key_bits' => 512, 'encrypt_key' => false));
     // Get private key
     $sprvkey = '';
     openssl_pkey_export($sres, $sprvkey);
     // Get public key
     $spkey = openssl_pkey_get_details($sres);
     $spubkey = $spkey["key"];
     $r = q("INSERT INTO `user` ( `guid`, `username`, `password`, `email`, `openid`, `nickname`,\n\t\t`pubkey`, `prvkey`, `spubkey`, `sprvkey`, `register_date`, `verified`, `blocked` )\n\t\tVALUES ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d )", dbesc(generate_user_guid()), dbesc($username), dbesc($new_password_encoded), dbesc($email), dbesc($openid_url), dbesc($nickname), dbesc($pubkey), dbesc($prvkey), dbesc($spubkey), dbesc($sprvkey), dbesc(datetime_convert()), intval($verified), intval($blocked));
     if ($r) {
         $r = q("SELECT `uid` FROM `user` \n\t\t\tWHERE `username` = '%s' AND `password` = '%s' LIMIT 1", dbesc($username), dbesc($new_password_encoded));
         if ($r !== false && count($r)) {
             $newuid = intval($r[0]['uid']);
         }
     } else {
         notice(t('An error occurred during registration. Please try again.') . EOL);
         return;
     }
     /**
      * if somebody clicked submit twice very quickly, they could end up with two accounts 
      * due to race condition. Remove this one.
      */
     $r = q("SELECT `uid` FROM `user`\n               \tWHERE `nickname` = '%s' ", dbesc($nickname));
     if (count($r) > 1 && $newuid) {
         $err .= t('Nickname is already registered. Please choose another.') . EOL;
         q("DELETE FROM `user` WHERE `uid` = %d LIMIT 1", intval($newuid));
         notice($err);
         return;
     }
     if (x($newuid) !== false) {
         $r = q("INSERT INTO `profile` ( `uid`, `profile-name`, `is-default`, `name`, `photo`, `thumb`, `publish`, `net-publish` )\n\t\t\tVALUES ( %d, '%s', %d, '%s', '%s', '%s', %d, %d ) ", intval($newuid), 'default', 1, dbesc($username), dbesc($a->get_baseurl() . "/photo/profile/{$newuid}.jpg"), dbesc($a->get_baseurl() . "/photo/avatar/{$newuid}.jpg"), intval($publish), intval($netpublish));
         if ($r === false) {
             notice(t('An error occurred creating your default profile. Please try again.') . EOL);
             // Start fresh next time.
             $r = q("DELETE FROM `user` WHERE `uid` = %d", intval($newuid));
             return;
         }
         $r = q("INSERT INTO `contact` ( `uid`, `created`, `self`, `name`, `nick`, `photo`, `thumb`, `micro`, `blocked`, `pending`, `url`, `nurl`,\n\t\t\t`request`, `notify`, `poll`, `confirm`, `poco`, `name-date`, `uri-date`, `avatar-date` )\n\t\t\tVALUES ( %d, '%s', 1, '%s', '%s', '%s', '%s', '%s', 0, 0, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", intval($newuid), datetime_convert(), dbesc($username), dbesc($nickname), dbesc($a->get_baseurl() . "/photo/profile/{$newuid}.jpg"), dbesc($a->get_baseurl() . "/photo/avatar/{$newuid}.jpg"), dbesc($a->get_baseurl() . "/photo/micro/{$newuid}.jpg"), dbesc($a->get_baseurl() . "/profile/{$nickname}"), dbesc(normalise_link($a->get_baseurl() . "/profile/{$nickname}")), dbesc($a->get_baseurl() . "/dfrn_request/{$nickname}"), dbesc($a->get_baseurl() . "/dfrn_notify/{$nickname}"), dbesc($a->get_baseurl() . "/dfrn_poll/{$nickname}"), dbesc($a->get_baseurl() . "/dfrn_confirm/{$nickname}"), dbesc($a->get_baseurl() . "/poco/{$nickname}"), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert()));
     }
     $use_gravatar = get_config('system', 'no_gravatar') ? false : true;
     // if we have an openid photo use it.
     // otherwise unless it is disabled, use gravatar
     if ($use_gravatar || strlen($photo)) {
         require_once 'include/Photo.php';
         if ($use_gravatar && !strlen($photo)) {
             $photo = gravatar_img($email);
         }
         $photo_failure = false;
         $filename = basename($photo);
         $img_str = fetch_url($photo, true);
         $img = new Photo($img_str);
         if ($img->is_valid()) {
             $img->scaleImageSquare(175);
             $hash = photo_new_resource();
             $r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 4);
             if ($r === false) {
                 $photo_failure = true;
             }
             $img->scaleImage(80);
             $r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 5);
             if ($r === false) {
                 $photo_failure = true;
             }
             $img->scaleImage(48);
             $r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 6);
             if ($r === false) {
                 $photo_failure = true;
             }
             if (!$photo_failure) {
                 q("UPDATE `photo` SET `profile` = 1 WHERE `resource-id` = '%s' ", dbesc($hash));
             }
         }
     }
     if ($netpublish && $a->config['register_policy'] != REGISTER_APPROVE) {
         $url = $a->get_baseurl() . "/profile/{$nickname}";
         proc_run('php', "include/directory.php", "{$url}");
     }
     call_hooks('register_account', $newuid);
     if ($a->config['register_policy'] == REGISTER_OPEN) {
         if ($using_invites && $invite_id) {
             q("delete * from register where hash = '%s' limit 1", dbesc($invite_id));
             set_pconfig($newuid, 'system', 'invites_remaining', $num_invites);
         }
         $email_tpl = get_intltext_template("register_open_eml.tpl");
         $email_tpl = replace_macros($email_tpl, array('$sitename' => $a->config['sitename'], '$siteurl' => $a->get_baseurl(), '$username' => $username, '$email' => $email, '$password' => $new_password, '$uid' => $newuid));
         $res = mail($email, sprintf(t('Registration details for %s'), $a->config['sitename']), $email_tpl, 'From: ' . t('Administrator') . '@' . $_SERVER['SERVER_NAME'] . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit');
         if ($res) {
             info(t('Registration successful. Please check your email for further instructions.') . EOL);
             goaway(z_root());
         } else {
             notice(t('Failed to send email message. Here is the message that failed.') . $email_tpl . EOL);
         }
     } elseif ($a->config['register_policy'] == REGISTER_APPROVE) {
         if (!strlen($a->config['admin_email'])) {
             notice(t('Your registration can not be processed.') . EOL);
             goaway(z_root());
         }
         $hash = random_string();
         $r = q("INSERT INTO `register` ( `hash`, `created`, `uid`, `password`, `language` ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ", dbesc($hash), dbesc(datetime_convert()), intval($newuid), dbesc($new_password), dbesc($lang));
         $r = q("SELECT `language` FROM `user` WHERE `email` = '%s' LIMIT 1", dbesc($a->config['admin_email']));
         if (count($r)) {
             push_lang($r[0]['language']);
         } else {
             push_lang('en');
         }
         if ($using_invites && $invite_id) {
             q("delete * from register where hash = '%s' limit 1", dbesc($invite_id));
             set_pconfig($newuid, 'system', 'invites_remaining', $num_invites);
         }
         $email_tpl = get_intltext_template("register_verify_eml.tpl");
         $email_tpl = replace_macros($email_tpl, array('$sitename' => $a->config['sitename'], '$siteurl' => $a->get_baseurl(), '$username' => $username, '$email' => $email, '$password' => $new_password, '$uid' => $newuid, '$hash' => $hash));
         $res = mail($a->config['admin_email'], sprintf(t('Registration request at %s'), $a->config['sitename']), $email_tpl, 'From: ' . t('Administrator') . '@' . $_SERVER['SERVER_NAME'] . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit');
         pop_lang();
         if ($res) {
             info(t('Your registration is pending approval by the site owner.') . EOL);
             goaway(z_root());
         }
     }
     return;
 }
Example #5
0
/**
 *
 * consume_feed - process atom feed and update anything/everything we might need to update
 *
 * $xml = the (atom) feed to consume - RSS isn't as fully supported but may work for simple feeds.
 *
 * $importer = the contact_record (joined to user_record) of the local user who owns this relationship.
 *             It is this person's stuff that is going to be updated.
 * $contact =  the person who is sending us stuff. If not set, we MAY be processing a "follow" activity
 *             from an external network and MAY create an appropriate contact record. Otherwise, we MUST 
 *             have a contact record.
 * $hub = should we find a hub declation in the feed, pass it back to our calling process, who might (or 
 *        might not) try and subscribe to it.
 * $datedir sorts in reverse order
 * $pass - by default ($pass = 0) we cannot guarantee that a parent item has been 
 *      imported prior to its children being seen in the stream unless we are certain
 *      of how the feed is arranged/ordered.
 * With $pass = 1, we only pull parent items out of the stream.
 * With $pass = 2, we only pull children (comments/likes).
 *
 * So running this twice, first with pass 1 and then with pass 2 will do the right
 * thing regardless of feed ordering. This won't be adequate in a fully-threaded
 * model where comments can have sub-threads. That would require some massive sorting
 * to get all the feed items into a mostly linear ordering, and might still require
 * recursion.  
 */
function consume_feed($xml, $importer, &$contact, &$hub, $datedir = 0, $pass = 0)
{
    require_once 'library/simplepie/simplepie.inc';
    if (!strlen($xml)) {
        logger('consume_feed: empty input');
        return;
    }
    $feed = new SimplePie();
    $feed->set_raw_data($xml);
    if ($datedir) {
        $feed->enable_order_by_date(true);
    } else {
        $feed->enable_order_by_date(false);
    }
    $feed->init();
    if ($feed->error()) {
        logger('consume_feed: Error parsing XML: ' . $feed->error());
    }
    $permalink = $feed->get_permalink();
    // Check at the feed level for updated contact name and/or photo
    $name_updated = '';
    $new_name = '';
    $photo_timestamp = '';
    $photo_url = '';
    $birthday = '';
    $hubs = $feed->get_links('hub');
    if (count($hubs)) {
        $hub = implode(',', $hubs);
    }
    $rawtags = $feed->get_feed_tags(NAMESPACE_DFRN, 'owner');
    if (!$rawtags) {
        $rawtags = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author');
    }
    if ($rawtags) {
        $elems = $rawtags[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10];
        if ($elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated']) {
            $name_updated = $elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated'];
            $new_name = $elems['name'][0]['data'];
        }
        if (x($elems, 'link') && $elems['link'][0]['attribs']['']['rel'] === 'photo' && $elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated']) {
            $photo_timestamp = datetime_convert('UTC', 'UTC', $elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated']);
            $photo_url = $elems['link'][0]['attribs']['']['href'];
        }
        if (x($rawtags[0]['child'], NAMESPACE_DFRN) && x($rawtags[0]['child'][NAMESPACE_DFRN], 'birthday')) {
            $birthday = datetime_convert('UTC', 'UTC', $rawtags[0]['child'][NAMESPACE_DFRN]['birthday'][0]['data']);
        }
    }
    if (is_array($contact) && $photo_timestamp && strlen($photo_url) && $photo_timestamp > $contact['avatar-date']) {
        logger('consume_feed: Updating photo for ' . $contact['name']);
        require_once "Photo.php";
        $photo_failure = false;
        $have_photo = false;
        $r = q("SELECT `resource-id` FROM `photo` WHERE `contact-id` = %d AND `uid` = %d LIMIT 1", intval($contact['id']), intval($contact['uid']));
        if (count($r)) {
            $resource_id = $r[0]['resource-id'];
            $have_photo = true;
        } else {
            $resource_id = photo_new_resource();
        }
        $img_str = fetch_url($photo_url, true);
        $img = new Photo($img_str);
        if ($img->is_valid()) {
            if ($have_photo) {
                q("DELETE FROM `photo` WHERE `resource-id` = '%s' AND `contact-id` = %d AND `uid` = %d", dbesc($resource_id), intval($contact['id']), intval($contact['uid']));
            }
            $img->scaleImageSquare(175);
            $hash = $resource_id;
            $r = $img->store($contact['uid'], $contact['id'], $hash, basename($photo_url), 'Contact Photos', 4);
            $img->scaleImage(80);
            $r = $img->store($contact['uid'], $contact['id'], $hash, basename($photo_url), 'Contact Photos', 5);
            $img->scaleImage(48);
            $r = $img->store($contact['uid'], $contact['id'], $hash, basename($photo_url), 'Contact Photos', 6);
            $a = get_app();
            q("UPDATE `contact` SET `avatar-date` = '%s', `photo` = '%s', `thumb` = '%s', `micro` = '%s'  \n\t\t\t\tWHERE `uid` = %d AND `id` = %d LIMIT 1", dbesc(datetime_convert()), dbesc($a->get_baseurl() . '/photo/' . $hash . '-4.jpg'), dbesc($a->get_baseurl() . '/photo/' . $hash . '-5.jpg'), dbesc($a->get_baseurl() . '/photo/' . $hash . '-6.jpg'), intval($contact['uid']), intval($contact['id']));
        }
    }
    if (is_array($contact) && $name_updated && strlen($new_name) && $name_updated > $contact['name-date']) {
        $r = q("select * from contact where uid = %d and id = %d limit 1", intval($contact['uid']), intval($contact['id']));
        $x = q("UPDATE `contact` SET `name` = '%s', `name-date` = '%s' WHERE `uid` = %d AND `id` = %d LIMIT 1", dbesc(notags(trim($new_name))), dbesc(datetime_convert()), intval($contact['uid']), intval($contact['id']));
        // do our best to update the name on content items
        if (count($r)) {
            q("update item set `author-name` = '%s' where `author-name` = '%s' and `author-link` = '%s' and uid = %d", dbesc(notags(trim($new_name))), dbesc($r[0]['name']), dbesc($r[0]['url']), intval($contact['uid']));
        }
    }
    if (strlen($birthday)) {
        if (substr($birthday, 0, 4) != $contact['bdyear']) {
            logger('consume_feed: updating birthday: ' . $birthday);
            /**
             *
             * Add new birthday event for this person
             *
             * $bdtext is just a readable placeholder in case the event is shared
             * with others. We will replace it during presentation to our $importer
             * to contain a sparkle link and perhaps a photo. 
             *
             */
            $bdtext = t('Birthday:') . ' [url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
            $r = q("INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`desc`,`type`)\n\t\t\t\tVALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s' ) ", intval($contact['uid']), intval($contact['id']), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert('UTC', 'UTC', $birthday)), dbesc(datetime_convert('UTC', 'UTC', $birthday . ' + 1 day ')), dbesc($bdtext), dbesc('birthday'));
            // update bdyear
            q("UPDATE `contact` SET `bdyear` = '%s' WHERE `uid` = %d AND `id` = %d LIMIT 1", dbesc(substr($birthday, 0, 4)), intval($contact['uid']), intval($contact['id']));
            // This function is called twice without reloading the contact
            // Make sure we only create one event. This is why &$contact
            // is a reference var in this function
            $contact['bdyear'] = substr($birthday, 0, 4);
        }
    }
    $community_page = 0;
    $rawtags = $feed->get_feed_tags(NAMESPACE_DFRN, 'community');
    if ($rawtags) {
        $community_page = intval($rawtags[0]['data']);
    }
    if (is_array($contact) && intval($contact['forum']) != $community_page) {
        q("update contact set forum = %d where id = %d limit 1", intval($community_page), intval($contact['id']));
        $contact['forum'] = (string) $community_page;
    }
    // process any deleted entries
    $del_entries = $feed->get_feed_tags(NAMESPACE_TOMB, 'deleted-entry');
    if (is_array($del_entries) && count($del_entries) && $pass != 2) {
        foreach ($del_entries as $dentry) {
            $deleted = false;
            if (isset($dentry['attribs']['']['ref'])) {
                $uri = $dentry['attribs']['']['ref'];
                $deleted = true;
                if (isset($dentry['attribs']['']['when'])) {
                    $when = $dentry['attribs']['']['when'];
                    $when = datetime_convert('UTC', 'UTC', $when, 'Y-m-d H:i:s');
                } else {
                    $when = datetime_convert('UTC', 'UTC', 'now', 'Y-m-d H:i:s');
                }
            }
            if ($deleted && is_array($contact)) {
                $r = q("SELECT `item`.*, `contact`.`self` FROM `item` left join `contact` on `item`.`contact-id` = `contact`.`id` \n\t\t\t\t\tWHERE `uri` = '%s' AND `item`.`uid` = %d AND `contact-id` = %d AND NOT `item`.`file` LIKE '%%[%%' LIMIT 1", dbesc($uri), intval($importer['uid']), intval($contact['id']));
                if (count($r)) {
                    $item = $r[0];
                    if (!$item['deleted']) {
                        logger('consume_feed: deleting item ' . $item['id'] . ' uri=' . $item['uri'], LOGGER_DEBUG);
                    }
                    if ($item['verb'] === ACTIVITY_TAG && $item['object-type'] === ACTIVITY_OBJ_TAGTERM) {
                        $xo = parse_xml_string($item['object'], false);
                        $xt = parse_xml_string($item['target'], false);
                        if ($xt->type === ACTIVITY_OBJ_NOTE) {
                            $i = q("select * from `item` where uri = '%s' and uid = %d limit 1", dbesc($xt->id), intval($importer['importer_uid']));
                            if (count($i)) {
                                // For tags, the owner cannot remove the tag on the author's copy of the post.
                                $owner_remove = $item['contact-id'] == $i[0]['contact-id'] ? true : false;
                                $author_remove = $item['origin'] && $item['self'] ? true : false;
                                $author_copy = $item['origin'] ? true : false;
                                if ($owner_remove && $author_copy) {
                                    continue;
                                }
                                if ($author_remove || $owner_remove) {
                                    $tags = explode(',', $i[0]['tag']);
                                    $newtags = array();
                                    if (count($tags)) {
                                        foreach ($tags as $tag) {
                                            if (trim($tag) !== trim($xo->body)) {
                                                $newtags[] = trim($tag);
                                            }
                                        }
                                    }
                                    q("update item set tag = '%s' where id = %d limit 1", dbesc(implode(',', $newtags)), intval($i[0]['id']));
                                }
                            }
                        }
                    }
                    if ($item['uri'] == $item['parent-uri']) {
                        $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',\n\t\t\t\t\t\t\t`body` = '', `title` = ''\n\t\t\t\t\t\t\tWHERE `parent-uri` = '%s' AND `uid` = %d", dbesc($when), dbesc(datetime_convert()), dbesc($item['uri']), intval($importer['uid']));
                    } else {
                        $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',\n\t\t\t\t\t\t\t`body` = '', `title` = '' \n\t\t\t\t\t\t\tWHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($when), dbesc(datetime_convert()), dbesc($uri), intval($importer['uid']));
                        if ($item['last-child']) {
                            // ensure that last-child is set in case the comment that had it just got wiped.
                            q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ", dbesc(datetime_convert()), dbesc($item['parent-uri']), intval($item['uid']));
                            // who is the last child now?
                            $r = q("SELECT `id` FROM `item` WHERE `parent-uri` = '%s' AND `type` != 'activity' AND `deleted` = 0 AND `moderated` = 0 AND `uid` = %d \n\t\t\t\t\t\t\t\tORDER BY `created` DESC LIMIT 1", dbesc($item['parent-uri']), intval($importer['uid']));
                            if (count($r)) {
                                q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d LIMIT 1", intval($r[0]['id']));
                            }
                        }
                    }
                }
            }
        }
    }
    // Now process the feed
    if ($feed->get_item_quantity()) {
        logger('consume_feed: feed item count = ' . $feed->get_item_quantity());
        // in inverse date order
        if ($datedir) {
            $items = array_reverse($feed->get_items());
        } else {
            $items = $feed->get_items();
        }
        foreach ($items as $item) {
            $is_reply = false;
            $item_id = $item->get_id();
            $rawthread = $item->get_item_tags(NAMESPACE_THREAD, 'in-reply-to');
            if (isset($rawthread[0]['attribs']['']['ref'])) {
                $is_reply = true;
                $parent_uri = $rawthread[0]['attribs']['']['ref'];
            }
            if ($is_reply && is_array($contact)) {
                if ($pass == 1) {
                    continue;
                }
                // Have we seen it? If not, import it.
                $item_id = $item->get_id();
                $datarray = get_atom_elements($feed, $item);
                if (!x($datarray, 'author-name') && $contact['network'] != NETWORK_DFRN) {
                    $datarray['author-name'] = $contact['name'];
                }
                if (!x($datarray, 'author-link') && $contact['network'] != NETWORK_DFRN) {
                    $datarray['author-link'] = $contact['url'];
                }
                if (!x($datarray, 'author-avatar') && $contact['network'] != NETWORK_DFRN) {
                    $datarray['author-avatar'] = $contact['thumb'];
                }
                if (!x($datarray, 'author-name') || !x($datarray, 'author-link')) {
                    logger('consume_feed: no author information! ' . print_r($datarray, true));
                    continue;
                }
                $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['uid']));
                // Update content if 'updated' changes
                if (count($r)) {
                    if (x($datarray, 'edited') !== false && datetime_convert('UTC', 'UTC', $datarray['edited']) !== $r[0]['edited']) {
                        $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['tag']), dbesc(datetime_convert('UTC', 'UTC', $datarray['edited'])), dbesc($item_id), intval($importer['uid']));
                    }
                    // update last-child if it changes
                    $allow = $item->get_item_tags(NAMESPACE_DFRN, 'comment-allow');
                    if ($allow && $allow[0]['data'] != $r[0]['last-child']) {
                        $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", dbesc(datetime_convert()), dbesc($parent_uri), intval($importer['uid']));
                        $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s'  WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", intval($allow[0]['data']), dbesc(datetime_convert()), dbesc($item_id), intval($importer['uid']));
                    }
                    continue;
                }
                $force_parent = false;
                if ($contact['network'] === NETWORK_OSTATUS || stristr($contact['url'], 'twitter.com')) {
                    if ($contact['network'] === NETWORK_OSTATUS) {
                        $force_parent = true;
                    }
                    if (strlen($datarray['title'])) {
                        unset($datarray['title']);
                    }
                    $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", dbesc(datetime_convert()), dbesc($parent_uri), intval($importer['uid']));
                    $datarray['last-child'] = 1;
                }
                if ($contact['network'] === NETWORK_FEED || !strlen($contact['notify'])) {
                    // one way feed - no remote comment ability
                    $datarray['last-child'] = 0;
                }
                $datarray['parent-uri'] = $parent_uri;
                $datarray['uid'] = $importer['uid'];
                $datarray['contact-id'] = $contact['id'];
                if (activity_match($datarray['verb'], ACTIVITY_LIKE) || activity_match($datarray['verb'], ACTIVITY_DISLIKE)) {
                    $datarray['type'] = 'activity';
                    $datarray['gravity'] = GRAVITY_LIKE;
                    // only one like or dislike per person
                    $r = q("select id from item where uid = %d and `contact-id` = %d and verb ='%s' and deleted = 0 limit 1", intval($datarray['uid']), intval($datarray['contact-id']), dbesc($datarray['verb']));
                    if ($r && count($r)) {
                        continue;
                    }
                }
                if ($datarray['verb'] === ACTIVITY_TAG && $datarray['object-type'] === ACTIVITY_OBJ_TAGTERM) {
                    $xo = parse_xml_string($datarray['object'], false);
                    $xt = parse_xml_string($datarray['target'], false);
                    if ($xt->type == ACTIVITY_OBJ_NOTE) {
                        $r = q("select * from item where `uri` = '%s' AND `uid` = %d limit 1", dbesc($xt->id), intval($importer['importer_uid']));
                        if (!count($r)) {
                            continue;
                        }
                        // extract tag, if not duplicate, add to parent item
                        if ($xo->id && $xo->content) {
                            $newtag = '#[url=' . $xo->id . ']' . $xo->content . '[/url]';
                            if (!stristr($r[0]['tag'], $newtag)) {
                                q("UPDATE item SET tag = '%s' WHERE id = %d LIMIT 1", dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . $newtag), intval($r[0]['id']));
                            }
                        }
                    }
                }
                $r = item_store($datarray, $force_parent);
                continue;
            } else {
                // Head post of a conversation. Have we seen it? If not, import it.
                $item_id = $item->get_id();
                $datarray = get_atom_elements($feed, $item);
                if (is_array($contact)) {
                    if (!x($datarray, 'author-name') && $contact['network'] != NETWORK_DFRN) {
                        $datarray['author-name'] = $contact['name'];
                    }
                    if (!x($datarray, 'author-link') && $contact['network'] != NETWORK_DFRN) {
                        $datarray['author-link'] = $contact['url'];
                    }
                    if (!x($datarray, 'author-avatar') && $contact['network'] != NETWORK_DFRN) {
                        $datarray['author-avatar'] = $contact['thumb'];
                    }
                }
                if (!x($datarray, 'author-name') || !x($datarray, 'author-link')) {
                    logger('consume_feed: no author information! ' . print_r($datarray, true));
                    continue;
                }
                // special handling for events
                if (x($datarray, 'object-type') && $datarray['object-type'] === ACTIVITY_OBJ_EVENT) {
                    $ev = bbtoevent($datarray['body']);
                    if (x($ev, 'desc') && x($ev, 'start')) {
                        $ev['uid'] = $importer['uid'];
                        $ev['uri'] = $item_id;
                        $ev['edited'] = $datarray['edited'];
                        $ev['private'] = $datarray['private'];
                        if (is_array($contact)) {
                            $ev['cid'] = $contact['id'];
                        }
                        $r = q("SELECT * FROM `event` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['uid']));
                        if (count($r)) {
                            $ev['id'] = $r[0]['id'];
                        }
                        $xyz = event_store($ev);
                        continue;
                    }
                }
                $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['uid']));
                // Update content if 'updated' changes
                if (count($r)) {
                    if (x($datarray, 'edited') !== false && datetime_convert('UTC', 'UTC', $datarray['edited']) !== $r[0]['edited']) {
                        $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['tag']), dbesc(datetime_convert('UTC', 'UTC', $datarray['edited'])), dbesc($item_id), intval($importer['uid']));
                    }
                    // update last-child if it changes
                    $allow = $item->get_item_tags(NAMESPACE_DFRN, 'comment-allow');
                    if ($allow && $allow[0]['data'] != $r[0]['last-child']) {
                        $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", intval($allow[0]['data']), dbesc(datetime_convert()), dbesc($item_id), intval($importer['uid']));
                    }
                    continue;
                }
                if (activity_match($datarray['verb'], ACTIVITY_FOLLOW)) {
                    logger('consume-feed: New follower');
                    new_follower($importer, $contact, $datarray, $item);
                    return;
                }
                if (activity_match($datarray['verb'], ACTIVITY_UNFOLLOW)) {
                    lose_follower($importer, $contact, $datarray, $item);
                    return;
                }
                if (activity_match($datarray['verb'], ACTIVITY_REQ_FRIEND)) {
                    logger('consume-feed: New friend request');
                    new_follower($importer, $contact, $datarray, $item, true);
                    return;
                }
                if (activity_match($datarray['verb'], ACTIVITY_UNFRIEND)) {
                    lose_sharer($importer, $contact, $datarray, $item);
                    return;
                }
                if (!is_array($contact)) {
                    return;
                }
                if ($contact['network'] === NETWORK_OSTATUS || stristr($contact['url'], 'twitter.com')) {
                    if (strlen($datarray['title'])) {
                        unset($datarray['title']);
                    }
                    $datarray['last-child'] = 1;
                }
                if ($contact['network'] === NETWORK_FEED || !strlen($contact['notify'])) {
                    // one way feed - no remote comment ability
                    $datarray['last-child'] = 0;
                }
                // This is my contact on another system, but it's really me.
                // Turn this into a wall post.
                if ($contact['remote_self']) {
                    $datarray['wall'] = 1;
                }
                $datarray['parent-uri'] = $item_id;
                $datarray['uid'] = $importer['uid'];
                $datarray['contact-id'] = $contact['id'];
                if (!link_compare($datarray['owner-link'], $contact['url'])) {
                    // The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery,
                    // but otherwise there's a possible data mixup on the sender's system.
                    // the tgroup delivery code called from item_store will correct it if it's a forum,
                    // but we're going to unconditionally correct it here so that the post will always be owned by our contact.
                    logger('consume_feed: Correcting item owner.', LOGGER_DEBUG);
                    $datarray['owner-name'] = $contact['name'];
                    $datarray['owner-link'] = $contact['url'];
                    $datarray['owner-avatar'] = $contact['thumb'];
                }
                $r = item_store($datarray);
                continue;
            }
        }
    }
}
Example #6
0
function import_profile_photo($photo, $uid, $cid)
{
    $a = get_app();
    $r = q("select `resource-id` from photo where `uid` = %d and `contact-id` = %d and `scale` = 4 and `album` = 'Contact Photos' limit 1", intval($uid), intval($cid));
    if (count($r) && strlen($r[0]['resource-id'])) {
        $hash = $r[0]['resource-id'];
    } else {
        $hash = photo_new_resource();
    }
    $photo_failure = false;
    $filename = basename($photo);
    $img_str = fetch_url($photo, true);
    $type = guess_image_type($photo, true);
    $img = new Photo($img_str, $type);
    if ($img->is_valid()) {
        $img->scaleImageSquare(175);
        $r = $img->store($uid, $cid, $hash, $filename, 'Contact Photos', 4);
        if ($r === false) {
            $photo_failure = true;
        }
        $img->scaleImage(80);
        $r = $img->store($uid, $cid, $hash, $filename, 'Contact Photos', 5);
        if ($r === false) {
            $photo_failure = true;
        }
        $img->scaleImage(48);
        $r = $img->store($uid, $cid, $hash, $filename, 'Contact Photos', 6);
        if ($r === false) {
            $photo_failure = true;
        }
        $photo = $a->get_baseurl() . '/photo/' . $hash . '-4.' . $img->getExt();
        $thumb = $a->get_baseurl() . '/photo/' . $hash . '-5.' . $img->getExt();
        $micro = $a->get_baseurl() . '/photo/' . $hash . '-6.' . $img->getExt();
    } else {
        $photo_failure = true;
    }
    if ($photo_failure) {
        $photo = $a->get_baseurl() . '/images/person-175.jpg';
        $thumb = $a->get_baseurl() . '/images/person-80.jpg';
        $micro = $a->get_baseurl() . '/images/person-48.jpg';
    }
    return array($photo, $thumb, $micro);
}
Example #7
0
function photo_init(&$a)
{
    switch ($a->argc) {
        case 4:
            $person = $a->argv[3];
            $customres = intval($a->argv[2]);
            $type = $a->argv[1];
            break;
        case 3:
            $person = $a->argv[2];
            $type = $a->argv[1];
            break;
        case 2:
            $photo = $a->argv[1];
            break;
        case 1:
        default:
            killme();
            // NOTREACHED
    }
    $default = 'images/default-profile.jpg';
    if (isset($type)) {
        /**
         * Profile photos
         */
        switch ($type) {
            case 'profile':
            case 'custom':
                $resolution = 4;
                break;
            case 'micro':
                $resolution = 6;
                $default = 'images/default-profile-mm.jpg';
                break;
            case 'avatar':
            default:
                $resolution = 5;
                $default = 'images/default-profile-sm.jpg';
                break;
        }
        $uid = str_replace('.jpg', '', $person);
        $r = q("SELECT * FROM `photo` WHERE `scale` = %d AND `uid` = %d AND `profile` = 1 LIMIT 1", intval($resolution), intval($uid));
        if (count($r)) {
            $data = $r[0]['data'];
        }
        if (!isset($data)) {
            $data = file_get_contents($default);
        }
    } else {
        /**
         * Other photos
         */
        $resolution = 0;
        $photo = str_replace('.jpg', '', $photo);
        if (substr($photo, -2, 1) == '-') {
            $resolution = intval(substr($photo, -1, 1));
            $photo = substr($photo, 0, -2);
        }
        $r = q("SELECT `uid` FROM `photo` WHERE `resource-id` = '%s' AND `scale` = %d LIMIT 1", dbesc($photo), intval($resolution));
        if (count($r)) {
            $sql_extra = permissions_sql($r[0]['uid']);
            // Now we'll see if we can access the photo
            $r = q("SELECT * FROM `photo` WHERE `resource-id` = '%s' AND `scale` = %d {$sql_extra} LIMIT 1", dbesc($photo), intval($resolution));
            if (count($r)) {
                $data = $r[0]['data'];
            } else {
                // Does the picture exist? It may be a remote person with no credentials,
                // but who should otherwise be able to view it. Show a default image to let
                // them know permissions was denied. It may be possible to view the image
                // through an authenticated profile visit.
                // There won't be many completely unauthorised people seeing this because
                // they won't have the photo link, so there's a reasonable chance that the person
                // might be able to obtain permission to view it.
                $r = q("SELECT * FROM `photo` WHERE `resource-id` = '%s' AND `scale` = %d LIMIT 1", dbesc($photo), intval($resolution));
                if (count($r)) {
                    $data = file_get_contents('images/nosign.jpg');
                }
            }
        }
    }
    if (!isset($data)) {
        killme();
        // NOTREACHED
    }
    if (intval($customres) && $customres > 0 && $customres < 500) {
        require_once 'include/Photo.php';
        $ph = new Photo($data);
        if ($ph->is_valid()) {
            $ph->scaleImageSquare($customres);
            $data = $ph->imageString();
        }
    }
    if (function_exists('header_remove')) {
        header_remove('Pragma');
        header_remove('pragma');
    }
    header("Content-type: image/jpeg");
    header("Expires: " . gmdate("D, d M Y H:i:s", time() + 3600 * 24) . " GMT");
    header("Cache-Control: max-age=" . 3600 * 24);
    echo $data;
    killme();
    // NOTREACHED
}
Example #8
0
function import_profile_photo($photo, $uid, $cid)
{
    $a = get_app();
    $photo_failure = false;
    $filename = basename($photo);
    $img_str = fetch_url($photo, true);
    $img = new Photo($img_str);
    if ($img->is_valid()) {
        $img->scaleImageSquare(175);
        $hash = photo_new_resource();
        $r = $img->store($uid, $cid, $hash, $filename, 'Contact Photos', 4);
        if ($r === false) {
            $photo_failure = true;
        }
        $img->scaleImage(80);
        $r = $img->store($uid, $cid, $hash, $filename, 'Contact Photos', 5);
        if ($r === false) {
            $photo_failure = true;
        }
        $img->scaleImage(48);
        $r = $img->store($uid, $cid, $hash, $filename, 'Contact Photos', 6);
        if ($r === false) {
            $photo_failure = true;
        }
        $photo = $a->get_baseurl() . '/photo/' . $hash . '-4.jpg';
        $thumb = $a->get_baseurl() . '/photo/' . $hash . '-5.jpg';
        $micro = $a->get_baseurl() . '/photo/' . $hash . '-6.jpg';
    } else {
        $photo_failure = true;
    }
    if ($photo_failure) {
        $photo = $a->get_baseurl() . '/images/default-profile.jpg';
        $thumb = $a->get_baseurl() . '/images/default-profile-sm.jpg';
        $micro = $a->get_baseurl() . '/images/default-profile-mm.jpg';
    }
    return array($photo, $thumb, $micro);
}
Example #9
0
function local_delivery($importer, $data)
{
    $a = get_app();
    logger(__FUNCTION__, LOGGER_TRACE);
    if ($importer['readonly']) {
        // We aren't receiving stuff from this person. But we will quietly ignore them
        // rather than a blatant "go away" message.
        logger('local_delivery: ignoring');
        return 0;
        //NOTREACHED
    }
    // Consume notification feed. This may differ from consuming a public feed in several ways
    // - might contain email or friend suggestions
    // - might contain remote followup to our message
    //		- in which case we need to accept it and then notify other conversants
    // - we may need to send various email notifications
    $feed = new SimplePie();
    $feed->set_raw_data($data);
    $feed->enable_order_by_date(false);
    $feed->init();
    if ($feed->error()) {
        logger('local_delivery: Error parsing XML: ' . $feed->error());
    }
    // Check at the feed level for updated contact name and/or photo
    $name_updated = '';
    $new_name = '';
    $photo_timestamp = '';
    $photo_url = '';
    $rawtags = $feed->get_feed_tags(NAMESPACE_DFRN, 'owner');
    // Fallback should not be needed here. If it isn't DFRN it won't have DFRN updated tags
    //	if(! $rawtags)
    //		$rawtags = $feed->get_feed_tags( SIMPLEPIE_NAMESPACE_ATOM_10, 'author');
    if ($rawtags) {
        $elems = $rawtags[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10];
        if ($elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated']) {
            $name_updated = $elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated'];
            $new_name = $elems['name'][0]['data'];
        }
        if (x($elems, 'link') && $elems['link'][0]['attribs']['']['rel'] === 'photo' && $elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated']) {
            $photo_timestamp = datetime_convert('UTC', 'UTC', $elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated']);
            $photo_url = $elems['link'][0]['attribs']['']['href'];
        }
    }
    if ($photo_timestamp && strlen($photo_url) && $photo_timestamp > $importer['avatar-date']) {
        logger('local_delivery: Updating photo for ' . $importer['name']);
        require_once "include/Photo.php";
        $photo_failure = false;
        $have_photo = false;
        $r = q("SELECT `resource-id` FROM `photo` WHERE `contact-id` = %d AND `uid` = %d LIMIT 1", intval($importer['id']), intval($importer['importer_uid']));
        if (count($r)) {
            $resource_id = $r[0]['resource-id'];
            $have_photo = true;
        } else {
            $resource_id = photo_new_resource();
        }
        $img_str = fetch_url($photo_url, true);
        // guess mimetype from headers or filename
        $type = guess_image_type($photo_url, true);
        $img = new Photo($img_str, $type);
        if ($img->is_valid()) {
            if ($have_photo) {
                q("DELETE FROM `photo` WHERE `resource-id` = '%s' AND `contact-id` = %d AND `uid` = %d", dbesc($resource_id), intval($importer['id']), intval($importer['importer_uid']));
            }
            $img->scaleImageSquare(175);
            $hash = $resource_id;
            $r = $img->store($importer['importer_uid'], $importer['id'], $hash, basename($photo_url), 'Contact Photos', 4);
            $img->scaleImage(80);
            $r = $img->store($importer['importer_uid'], $importer['id'], $hash, basename($photo_url), 'Contact Photos', 5);
            $img->scaleImage(48);
            $r = $img->store($importer['importer_uid'], $importer['id'], $hash, basename($photo_url), 'Contact Photos', 6);
            $a = get_app();
            q("UPDATE `contact` SET `avatar-date` = '%s', `photo` = '%s', `thumb` = '%s', `micro` = '%s'\n\t\t\t\tWHERE `uid` = %d AND `id` = %d LIMIT 1", dbesc(datetime_convert()), dbesc($a->get_baseurl() . '/photo/' . $hash . '-4.' . $img->getExt()), dbesc($a->get_baseurl() . '/photo/' . $hash . '-5.' . $img->getExt()), dbesc($a->get_baseurl() . '/photo/' . $hash . '-6.' . $img->getExt()), intval($importer['importer_uid']), intval($importer['id']));
        }
    }
    if ($name_updated && strlen($new_name) && $name_updated > $importer['name-date']) {
        $r = q("select * from contact where uid = %d and id = %d limit 1", intval($importer['importer_uid']), intval($importer['id']));
        $x = q("UPDATE `contact` SET `name` = '%s', `name-date` = '%s' WHERE `uid` = %d AND `id` = %d LIMIT 1", dbesc(notags(trim($new_name))), dbesc(datetime_convert()), intval($importer['importer_uid']), intval($importer['id']));
        // do our best to update the name on content items
        if (count($r)) {
            q("update item set `author-name` = '%s' where `author-name` = '%s' and `author-link` = '%s' and uid = %d", dbesc(notags(trim($new_name))), dbesc($r[0]['name']), dbesc($r[0]['url']), intval($importer['importer_uid']));
        }
    }
    // Currently unsupported - needs a lot of work
    $reloc = $feed->get_feed_tags(NAMESPACE_DFRN, 'relocate');
    if (isset($reloc[0]['child'][NAMESPACE_DFRN])) {
        $base = $reloc[0]['child'][NAMESPACE_DFRN];
        $newloc = array();
        $newloc['uid'] = $importer['importer_uid'];
        $newloc['cid'] = $importer['id'];
        $newloc['name'] = notags(unxmlify($base['name'][0]['data']));
        $newloc['photo'] = notags(unxmlify($base['photo'][0]['data']));
        $newloc['thumb'] = notags(unxmlify($base['thumb'][0]['data']));
        $newloc['micro'] = notags(unxmlify($base['micro'][0]['data']));
        $newloc['url'] = notags(unxmlify($base['url'][0]['data']));
        $newloc['request'] = notags(unxmlify($base['request'][0]['data']));
        $newloc['confirm'] = notags(unxmlify($base['confirm'][0]['data']));
        $newloc['notify'] = notags(unxmlify($base['notify'][0]['data']));
        $newloc['poll'] = notags(unxmlify($base['poll'][0]['data']));
        $newloc['sitepubkey'] = notags(unxmlify($base['sitepubkey'][0]['data']));
        /** relocated user must have original key pair */
        /*$newloc['pubkey'] = notags(unxmlify($base['pubkey'][0]['data']));
        		$newloc['prvkey'] = notags(unxmlify($base['prvkey'][0]['data']));*/
        logger("items:relocate contact " . print_r($newloc, true) . print_r($importer, true), LOGGER_DEBUG);
        // update contact
        $r = q("SELECT photo, url FROM contact WHERE id=%d AND uid=%d;", intval($importer['id']), intval($importer['importer_uid']));
        if ($r === false) {
            return 1;
        }
        $old = $r[0];
        $x = q("UPDATE contact SET\n                        name = '%s',\n                        photo = '%s',\n                        thumb = '%s',\n                        micro = '%s',\n                        url = '%s',\n                        request = '%s',\n                        confirm = '%s',\n                        notify = '%s',\n                        poll = '%s',\n                        `site-pubkey` = '%s'\n                WHERE id=%d AND uid=%d;", dbesc($newloc['name']), dbesc($newloc['photo']), dbesc($newloc['thumb']), dbesc($newloc['micro']), dbesc($newloc['url']), dbesc($newloc['request']), dbesc($newloc['confirm']), dbesc($newloc['notify']), dbesc($newloc['poll']), dbesc($newloc['sitepubkey']), intval($importer['id']), intval($importer['importer_uid']));
        if ($x === false) {
            return 1;
        }
        // update items
        $fields = array('owner-link' => array($old['url'], $newloc['url']), 'author-link' => array($old['url'], $newloc['url']), 'owner-avatar' => array($old['photo'], $newloc['photo']), 'author-avatar' => array($old['photo'], $newloc['photo']));
        foreach ($fields as $n => $f) {
            $x = q("UPDATE item SET `%s`='%s' WHERE `%s`='%s' AND uid=%d", $n, dbesc($f[1]), $n, dbesc($f[0]), intval($importer['importer_uid']));
            if ($x === false) {
                return 1;
            }
        }
        // TODO
        // merge with current record, current contents have priority
        // update record, set url-updated
        // update profile photos
        // schedule a scan?
        return 0;
    }
    // handle friend suggestion notification
    $sugg = $feed->get_feed_tags(NAMESPACE_DFRN, 'suggest');
    if (isset($sugg[0]['child'][NAMESPACE_DFRN])) {
        $base = $sugg[0]['child'][NAMESPACE_DFRN];
        $fsugg = array();
        $fsugg['uid'] = $importer['importer_uid'];
        $fsugg['cid'] = $importer['id'];
        $fsugg['name'] = notags(unxmlify($base['name'][0]['data']));
        $fsugg['photo'] = notags(unxmlify($base['photo'][0]['data']));
        $fsugg['url'] = notags(unxmlify($base['url'][0]['data']));
        $fsugg['request'] = notags(unxmlify($base['request'][0]['data']));
        $fsugg['body'] = escape_tags(unxmlify($base['note'][0]['data']));
        // Does our member already have a friend matching this description?
        $r = q("SELECT * FROM `contact` WHERE `name` = '%s' AND `nurl` = '%s' AND `uid` = %d LIMIT 1", dbesc($fsugg['name']), dbesc(normalise_link($fsugg['url'])), intval($fsugg['uid']));
        if (count($r)) {
            return 0;
        }
        // Do we already have an fcontact record for this person?
        $fid = 0;
        $r = q("SELECT * FROM `fcontact` WHERE `url` = '%s' AND `name` = '%s' AND `request` = '%s' LIMIT 1", dbesc($fsugg['url']), dbesc($fsugg['name']), dbesc($fsugg['request']));
        if (count($r)) {
            $fid = $r[0]['id'];
            // OK, we do. Do we already have an introduction for this person ?
            $r = q("select id from intro where uid = %d and fid = %d limit 1", intval($fsugg['uid']), intval($fid));
            if (count($r)) {
                return 0;
            }
        }
        if (!$fid) {
            $r = q("INSERT INTO `fcontact` ( `name`,`url`,`photo`,`request` ) VALUES ( '%s', '%s', '%s', '%s' ) ", dbesc($fsugg['name']), dbesc($fsugg['url']), dbesc($fsugg['photo']), dbesc($fsugg['request']));
        }
        $r = q("SELECT * FROM `fcontact` WHERE `url` = '%s' AND `name` = '%s' AND `request` = '%s' LIMIT 1", dbesc($fsugg['url']), dbesc($fsugg['name']), dbesc($fsugg['request']));
        if (count($r)) {
            $fid = $r[0]['id'];
        } else {
            return 0;
        }
        $hash = random_string();
        $r = q("INSERT INTO `intro` ( `uid`, `fid`, `contact-id`, `note`, `hash`, `datetime`, `blocked` )\n\t\t\tVALUES( %d, %d, %d, '%s', '%s', '%s', %d )", intval($fsugg['uid']), intval($fid), intval($fsugg['cid']), dbesc($fsugg['body']), dbesc($hash), dbesc(datetime_convert()), intval(0));
        notification(array('type' => NOTIFY_SUGGEST, 'notify_flags' => $importer['notify-flags'], 'language' => $importer['language'], 'to_name' => $importer['username'], 'to_email' => $importer['email'], 'uid' => $importer['importer_uid'], 'item' => $fsugg, 'link' => $a->get_baseurl() . '/notifications/intros', 'source_name' => $importer['name'], 'source_link' => $importer['url'], 'source_photo' => $importer['photo'], 'verb' => ACTIVITY_REQ_FRIEND, 'otype' => 'intro'));
        return 0;
    }
    $ismail = false;
    $rawmail = $feed->get_feed_tags(NAMESPACE_DFRN, 'mail');
    if (isset($rawmail[0]['child'][NAMESPACE_DFRN])) {
        logger('local_delivery: private message received');
        $ismail = true;
        $base = $rawmail[0]['child'][NAMESPACE_DFRN];
        $msg = array();
        $msg['uid'] = $importer['importer_uid'];
        $msg['from-name'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['name'][0]['data']));
        $msg['from-photo'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['avatar'][0]['data']));
        $msg['from-url'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['uri'][0]['data']));
        $msg['contact-id'] = $importer['id'];
        $msg['title'] = notags(unxmlify($base['subject'][0]['data']));
        $msg['body'] = escape_tags(unxmlify($base['content'][0]['data']));
        $msg['seen'] = 0;
        $msg['replied'] = 0;
        $msg['uri'] = notags(unxmlify($base['id'][0]['data']));
        $msg['parent-uri'] = notags(unxmlify($base['in-reply-to'][0]['data']));
        $msg['created'] = datetime_convert(notags(unxmlify('UTC', 'UTC', $base['sentdate'][0]['data'])));
        dbesc_array($msg);
        $r = dbq("INSERT INTO `mail` (`" . implode("`, `", array_keys($msg)) . "`) VALUES ('" . implode("', '", array_values($msg)) . "')");
        // send notifications.
        require_once 'include/enotify.php';
        $notif_params = array('type' => NOTIFY_MAIL, 'notify_flags' => $importer['notify-flags'], 'language' => $importer['language'], 'to_name' => $importer['username'], 'to_email' => $importer['email'], 'uid' => $importer['importer_uid'], 'item' => $msg, 'source_name' => $msg['from-name'], 'source_link' => $importer['url'], 'source_photo' => $importer['thumb'], 'verb' => ACTIVITY_POST, 'otype' => 'mail');
        notification($notif_params);
        return 0;
        // NOTREACHED
    }
    $community_page = 0;
    $rawtags = $feed->get_feed_tags(NAMESPACE_DFRN, 'community');
    if ($rawtags) {
        $community_page = intval($rawtags[0]['data']);
    }
    if (intval($importer['forum']) != $community_page) {
        q("update contact set forum = %d where id = %d limit 1", intval($community_page), intval($importer['id']));
        $importer['forum'] = (string) $community_page;
    }
    logger('local_delivery: feed item count = ' . $feed->get_item_quantity());
    // process any deleted entries
    $del_entries = $feed->get_feed_tags(NAMESPACE_TOMB, 'deleted-entry');
    if (is_array($del_entries) && count($del_entries)) {
        foreach ($del_entries as $dentry) {
            $deleted = false;
            if (isset($dentry['attribs']['']['ref'])) {
                $uri = $dentry['attribs']['']['ref'];
                $deleted = true;
                if (isset($dentry['attribs']['']['when'])) {
                    $when = $dentry['attribs']['']['when'];
                    $when = datetime_convert('UTC', 'UTC', $when, 'Y-m-d H:i:s');
                } else {
                    $when = datetime_convert('UTC', 'UTC', 'now', 'Y-m-d H:i:s');
                }
            }
            if ($deleted) {
                // check for relayed deletes to our conversation
                $is_reply = false;
                $r = q("select * from item where uri = '%s' and uid = %d limit 1", dbesc($uri), intval($importer['importer_uid']));
                if (count($r)) {
                    $parent_uri = $r[0]['parent-uri'];
                    if ($r[0]['id'] != $r[0]['parent']) {
                        $is_reply = true;
                    }
                }
                if ($is_reply) {
                    $community = false;
                    if ($importer['page-flags'] == PAGE_COMMUNITY || $importer['page-flags'] == PAGE_PRVGROUP) {
                        $sql_extra = '';
                        $community = true;
                        logger('local_delivery: possible community delete');
                    } else {
                        $sql_extra = " and contact.self = 1 and item.wall = 1 ";
                    }
                    // was the top-level post for this reply written by somebody on this site?
                    // Specifically, the recipient?
                    $is_a_remote_delete = false;
                    // POSSIBLE CLEANUP --> Why select so many fields when only forum_mode and wall are used?
                    $r = q("select `item`.`id`, `item`.`uri`, `item`.`tag`, `item`.`forum_mode`,`item`.`origin`,`item`.`wall`, \n\t\t\t\t\t\t`contact`.`name`, `contact`.`url`, `contact`.`thumb` from `item` \n\t\t\t\t\t\tLEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id` \n\t\t\t\t\t\tWHERE `item`.`uri` = '%s' AND (`item`.`parent-uri` = '%s' or `item`.`thr-parent` = '%s')\n\t\t\t\t\t\tAND `item`.`uid` = %d \n\t\t\t\t\t\t{$sql_extra}\n\t\t\t\t\t\tLIMIT 1", dbesc($parent_uri), dbesc($parent_uri), dbesc($parent_uri), intval($importer['importer_uid']));
                    if ($r && count($r)) {
                        $is_a_remote_delete = true;
                    }
                    // Does this have the characteristics of a community or private group comment?
                    // If it's a reply to a wall post on a community/prvgroup page it's a
                    // valid community comment. Also forum_mode makes it valid for sure.
                    // If neither, it's not.
                    if ($is_a_remote_delete && $community) {
                        if (!$r[0]['forum_mode'] && !$r[0]['wall']) {
                            $is_a_remote_delete = false;
                            logger('local_delivery: not a community delete');
                        }
                    }
                    if ($is_a_remote_delete) {
                        logger('local_delivery: received remote delete');
                    }
                }
                $r = q("SELECT `item`.*, `contact`.`self` FROM `item` left join contact on `item`.`contact-id` = `contact`.`id`\n\t\t\t\t\tWHERE `uri` = '%s' AND `item`.`uid` = %d AND `contact-id` = %d AND NOT `item`.`file` LIKE '%%[%%' LIMIT 1", dbesc($uri), intval($importer['importer_uid']), intval($importer['id']));
                if (count($r)) {
                    $item = $r[0];
                    if ($item['deleted']) {
                        continue;
                    }
                    logger('local_delivery: deleting item ' . $item['id'] . ' uri=' . $item['uri'], LOGGER_DEBUG);
                    if ($item['verb'] === ACTIVITY_TAG && $item['object-type'] === ACTIVITY_OBJ_TAGTERM) {
                        $xo = parse_xml_string($item['object'], false);
                        $xt = parse_xml_string($item['target'], false);
                        if ($xt->type === ACTIVITY_OBJ_NOTE) {
                            $i = q("select * from `item` where uri = '%s' and uid = %d limit 1", dbesc($xt->id), intval($importer['importer_uid']));
                            if (count($i)) {
                                // For tags, the owner cannot remove the tag on the author's copy of the post.
                                $owner_remove = $item['contact-id'] == $i[0]['contact-id'] ? true : false;
                                $author_remove = $item['origin'] && $item['self'] ? true : false;
                                $author_copy = $item['origin'] ? true : false;
                                if ($owner_remove && $author_copy) {
                                    continue;
                                }
                                if ($author_remove || $owner_remove) {
                                    $tags = explode(',', $i[0]['tag']);
                                    $newtags = array();
                                    if (count($tags)) {
                                        foreach ($tags as $tag) {
                                            if (trim($tag) !== trim($xo->body)) {
                                                $newtags[] = trim($tag);
                                            }
                                        }
                                    }
                                    q("update item set tag = '%s' where id = %d limit 1", dbesc(implode(',', $newtags)), intval($i[0]['id']));
                                    create_tags_from_item($i[0]['id']);
                                }
                            }
                        }
                    }
                    if ($item['uri'] == $item['parent-uri']) {
                        $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',\n\t\t\t\t\t\t\t`body` = '', `title` = ''\n\t\t\t\t\t\t\tWHERE `parent-uri` = '%s' AND `uid` = %d", dbesc($when), dbesc(datetime_convert()), dbesc($item['uri']), intval($importer['importer_uid']));
                        create_tags_from_itemuri($item['uri'], $importer['importer_uid']);
                    } else {
                        $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',\n\t\t\t\t\t\t\t`body` = '', `title` = ''\n\t\t\t\t\t\t\tWHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($when), dbesc(datetime_convert()), dbesc($uri), intval($importer['importer_uid']));
                        create_tags_from_itemuri($uri, $importer['importer_uid']);
                        if ($item['last-child']) {
                            // ensure that last-child is set in case the comment that had it just got wiped.
                            q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ", dbesc(datetime_convert()), dbesc($item['parent-uri']), intval($item['uid']));
                            // who is the last child now?
                            $r = q("SELECT `id` FROM `item` WHERE `parent-uri` = '%s' AND `type` != 'activity' AND `deleted` = 0 AND `uid` = %d\n\t\t\t\t\t\t\t\tORDER BY `created` DESC LIMIT 1", dbesc($item['parent-uri']), intval($importer['importer_uid']));
                            if (count($r)) {
                                q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d LIMIT 1", intval($r[0]['id']));
                            }
                        }
                        // if this is a relayed delete, propagate it to other recipients
                        if ($is_a_remote_delete) {
                            proc_run('php', "include/notifier.php", "drop", $item['id']);
                        }
                    }
                }
            }
        }
    }
    foreach ($feed->get_items() as $item) {
        $is_reply = false;
        $item_id = $item->get_id();
        $rawthread = $item->get_item_tags(NAMESPACE_THREAD, 'in-reply-to');
        if (isset($rawthread[0]['attribs']['']['ref'])) {
            $is_reply = true;
            $parent_uri = $rawthread[0]['attribs']['']['ref'];
        }
        if ($is_reply) {
            $community = false;
            if ($importer['page-flags'] == PAGE_COMMUNITY || $importer['page-flags'] == PAGE_PRVGROUP) {
                $sql_extra = '';
                $community = true;
                logger('local_delivery: possible community reply');
            } else {
                $sql_extra = " and contact.self = 1 and item.wall = 1 ";
            }
            // was the top-level post for this reply written by somebody on this site?
            // Specifically, the recipient?
            $is_a_remote_comment = false;
            $top_uri = $parent_uri;
            $r = q("select `item`.`parent-uri` from `item`\n\t\t\t\tWHERE `item`.`uri` = '%s'\n\t\t\t\tLIMIT 1", dbesc($parent_uri));
            if ($r && count($r)) {
                $top_uri = $r[0]['parent-uri'];
                // POSSIBLE CLEANUP --> Why select so many fields when only forum_mode and wall are used?
                $r = q("select `item`.`id`, `item`.`uri`, `item`.`tag`, `item`.`forum_mode`,`item`.`origin`,`item`.`wall`, \n\t\t\t\t\t`contact`.`name`, `contact`.`url`, `contact`.`thumb` from `item` \n\t\t\t\t\tLEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id` \n\t\t\t\t\tWHERE `item`.`uri` = '%s' AND (`item`.`parent-uri` = '%s' or `item`.`thr-parent` = '%s')\n\t\t\t\t\tAND `item`.`uid` = %d \n\t\t\t\t\t{$sql_extra}\n\t\t\t\t\tLIMIT 1", dbesc($top_uri), dbesc($top_uri), dbesc($top_uri), intval($importer['importer_uid']));
                if ($r && count($r)) {
                    $is_a_remote_comment = true;
                }
            }
            // Does this have the characteristics of a community or private group comment?
            // If it's a reply to a wall post on a community/prvgroup page it's a
            // valid community comment. Also forum_mode makes it valid for sure.
            // If neither, it's not.
            if ($is_a_remote_comment && $community) {
                if (!$r[0]['forum_mode'] && !$r[0]['wall']) {
                    $is_a_remote_comment = false;
                    logger('local_delivery: not a community reply');
                }
            }
            if ($is_a_remote_comment) {
                logger('local_delivery: received remote comment');
                $is_like = false;
                // remote reply to our post. Import and then notify everybody else.
                $datarray = get_atom_elements($feed, $item);
                $r = q("SELECT `id`, `uid`, `last-child`, `edited`, `body`  FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['importer_uid']));
                // Update content if 'updated' changes
                if (count($r)) {
                    $iid = $r[0]['id'];
                    if (x($datarray, 'edited') !== false && datetime_convert('UTC', 'UTC', $datarray['edited']) !== $r[0]['edited']) {
                        // do not accept (ignore) an earlier edit than one we currently have.
                        if (datetime_convert('UTC', 'UTC', $datarray['edited']) < $r[0]['edited']) {
                            continue;
                        }
                        logger('received updated comment', LOGGER_DEBUG);
                        $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['tag']), dbesc(datetime_convert('UTC', 'UTC', $datarray['edited'])), dbesc($item_id), intval($importer['importer_uid']));
                        create_tags_from_itemuri($item_id, $importer['importer_uid']);
                        proc_run('php', "include/notifier.php", "comment-import", $iid);
                    }
                    continue;
                }
                $own = q("select name,url,thumb from contact where uid = %d and self = 1 limit 1", intval($importer['importer_uid']));
                $datarray['type'] = 'remote-comment';
                $datarray['wall'] = 1;
                $datarray['parent-uri'] = $parent_uri;
                $datarray['uid'] = $importer['importer_uid'];
                $datarray['owner-name'] = $own[0]['name'];
                $datarray['owner-link'] = $own[0]['url'];
                $datarray['owner-avatar'] = $own[0]['thumb'];
                $datarray['contact-id'] = $importer['id'];
                if ($datarray['verb'] === ACTIVITY_LIKE || $datarray['verb'] === ACTIVITY_DISLIKE) {
                    $is_like = true;
                    $datarray['type'] = 'activity';
                    $datarray['gravity'] = GRAVITY_LIKE;
                    $datarray['last-child'] = 0;
                    // only one like or dislike per person
                    $r = q("select id from item where uid = %d and `contact-id` = %d and verb = '%s' and (`thr-parent` = '%s' or `parent-uri` = '%s') and deleted = 0 limit 1", intval($datarray['uid']), intval($datarray['contact-id']), dbesc($datarray['verb']), dbesc($datarray['parent-uri']), dbesc($datarray['parent-uri']));
                    if ($r && count($r)) {
                        continue;
                    }
                }
                if ($datarray['verb'] === ACTIVITY_TAG && $datarray['object-type'] === ACTIVITY_OBJ_TAGTERM) {
                    $xo = parse_xml_string($datarray['object'], false);
                    $xt = parse_xml_string($datarray['target'], false);
                    if ($xt->type == ACTIVITY_OBJ_NOTE && $xt->id) {
                        // fetch the parent item
                        $tagp = q("select * from item where uri = '%s' and uid = %d limit 1", dbesc($xt->id), intval($importer['importer_uid']));
                        if (!count($tagp)) {
                            continue;
                        }
                        // extract tag, if not duplicate, and this user allows tags, add to parent item
                        if ($xo->id && $xo->content) {
                            $newtag = '#[url=' . $xo->id . ']' . $xo->content . '[/url]';
                            if (!stristr($tagp[0]['tag'], $newtag)) {
                                $i = q("SELECT `blocktags` FROM `user` where `uid` = %d LIMIT 1", intval($importer['importer_uid']));
                                if (count($i) && !intval($i[0]['blocktags'])) {
                                    q("UPDATE item SET tag = '%s', `edited` = '%s' WHERE id = %d LIMIT 1", dbesc($tagp[0]['tag'] . (strlen($tagp[0]['tag']) ? ',' : '') . $newtag), intval($tagp[0]['id']), dbesc(datetime_convert()));
                                    create_tags_from_item($tagp[0]['id']);
                                }
                            }
                        }
                    }
                }
                $posted_id = item_store($datarray);
                $parent = 0;
                if ($posted_id) {
                    $r = q("SELECT `parent`, `parent-uri` FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($posted_id), intval($importer['importer_uid']));
                    if (count($r)) {
                        $parent = $r[0]['parent'];
                        $parent_uri = $r[0]['parent-uri'];
                    }
                    if (!$is_like) {
                        $r1 = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `uid` = %d AND `parent` = %d", dbesc(datetime_convert()), intval($importer['importer_uid']), intval($r[0]['parent']));
                        $r2 = q("UPDATE `item` SET `last-child` = 1, `changed` = '%s' WHERE `uid` = %d AND `id` = %d LIMIT 1", dbesc(datetime_convert()), intval($importer['importer_uid']), intval($posted_id));
                    }
                    if ($posted_id && $parent) {
                        proc_run('php', "include/notifier.php", "comment-import", "{$posted_id}");
                        if (!$is_like && !$importer['self']) {
                            require_once 'include/enotify.php';
                            notification(array('type' => NOTIFY_COMMENT, 'notify_flags' => $importer['notify-flags'], 'language' => $importer['language'], 'to_name' => $importer['username'], 'to_email' => $importer['email'], 'uid' => $importer['importer_uid'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $posted_id, 'source_name' => stripslashes($datarray['author-name']), 'source_link' => $datarray['author-link'], 'source_photo' => link_compare($datarray['author-link'], $importer['url']) ? $importer['thumb'] : $datarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item', 'parent' => $parent, 'parent_uri' => $parent_uri));
                        }
                    }
                    return 0;
                    // NOTREACHED
                }
            } else {
                // regular comment that is part of this total conversation. Have we seen it? If not, import it.
                $item_id = $item->get_id();
                $datarray = get_atom_elements($feed, $item);
                if ($importer['rel'] == CONTACT_IS_FOLLOWER) {
                    continue;
                }
                $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['importer_uid']));
                // Update content if 'updated' changes
                if (count($r)) {
                    if (x($datarray, 'edited') !== false && datetime_convert('UTC', 'UTC', $datarray['edited']) !== $r[0]['edited']) {
                        // do not accept (ignore) an earlier edit than one we currently have.
                        if (datetime_convert('UTC', 'UTC', $datarray['edited']) < $r[0]['edited']) {
                            continue;
                        }
                        $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['tag']), dbesc(datetime_convert('UTC', 'UTC', $datarray['edited'])), dbesc($item_id), intval($importer['importer_uid']));
                        create_tags_from_itemuri($item_id, $importer['importer_uid']);
                    }
                    // update last-child if it changes
                    $allow = $item->get_item_tags(NAMESPACE_DFRN, 'comment-allow');
                    if ($allow && $allow[0]['data'] != $r[0]['last-child']) {
                        $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", dbesc(datetime_convert()), dbesc($parent_uri), intval($importer['importer_uid']));
                        $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s'  WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", intval($allow[0]['data']), dbesc(datetime_convert()), dbesc($item_id), intval($importer['importer_uid']));
                    }
                    continue;
                }
                $datarray['parent-uri'] = $parent_uri;
                $datarray['uid'] = $importer['importer_uid'];
                $datarray['contact-id'] = $importer['id'];
                if ($datarray['verb'] == ACTIVITY_LIKE || $datarray['verb'] == ACTIVITY_DISLIKE) {
                    $datarray['type'] = 'activity';
                    $datarray['gravity'] = GRAVITY_LIKE;
                    // only one like or dislike per person
                    $r = q("select id from item where uid = %d and `contact-id` = %d and verb ='%s' and deleted = 0 and (`parent-uri` = '%s' OR `thr-parent` = '%s') limit 1", intval($datarray['uid']), intval($datarray['contact-id']), dbesc($datarray['verb']), dbesc($parent_uri), dbesc($parent_uri));
                    if ($r && count($r)) {
                        continue;
                    }
                }
                if ($datarray['verb'] === ACTIVITY_TAG && $datarray['object-type'] === ACTIVITY_OBJ_TAGTERM) {
                    $xo = parse_xml_string($datarray['object'], false);
                    $xt = parse_xml_string($datarray['target'], false);
                    if ($xt->type == ACTIVITY_OBJ_NOTE) {
                        $r = q("select * from item where `uri` = '%s' AND `uid` = %d limit 1", dbesc($xt->id), intval($importer['importer_uid']));
                        if (!count($r)) {
                            continue;
                        }
                        // extract tag, if not duplicate, add to parent item
                        if ($xo->content) {
                            if (!stristr($r[0]['tag'], trim($xo->content))) {
                                q("UPDATE item SET tag = '%s' WHERE id = %d LIMIT 1", dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . '#[url=' . $xo->id . ']' . $xo->content . '[/url]'), intval($r[0]['id']));
                                create_tags_from_item($r[0]['id']);
                            }
                        }
                    }
                }
                $posted_id = item_store($datarray);
                // find out if our user is involved in this conversation and wants to be notified.
                if (!x($datarray['type']) || $datarray['type'] != 'activity') {
                    $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 AND `deleted` = 0", dbesc($top_uri), intval($importer['importer_uid']));
                    if (count($myconv)) {
                        $importer_url = $a->get_baseurl() . '/profile/' . $importer['nickname'];
                        // first make sure this isn't our own post coming back to us from a wall-to-wall event
                        if (!link_compare($datarray['author-link'], $importer_url)) {
                            foreach ($myconv as $conv) {
                                // now if we find a match, it means we're in this conversation
                                if (!link_compare($conv['author-link'], $importer_url)) {
                                    continue;
                                }
                                require_once 'include/enotify.php';
                                $conv_parent = $conv['parent'];
                                notification(array('type' => NOTIFY_COMMENT, 'notify_flags' => $importer['notify-flags'], 'language' => $importer['language'], 'to_name' => $importer['username'], 'to_email' => $importer['email'], 'uid' => $importer['importer_uid'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $posted_id, 'source_name' => stripslashes($datarray['author-name']), 'source_link' => $datarray['author-link'], 'source_photo' => link_compare($datarray['author-link'], $importer['url']) ? $importer['thumb'] : $datarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item', 'parent' => $conv_parent, 'parent_uri' => $parent_uri));
                                // only send one notification
                                break;
                            }
                        }
                    }
                }
                continue;
            }
        } else {
            // Head post of a conversation. Have we seen it? If not, import it.
            $item_id = $item->get_id();
            $datarray = get_atom_elements($feed, $item);
            if (x($datarray, 'object-type') && $datarray['object-type'] === ACTIVITY_OBJ_EVENT) {
                $ev = bbtoevent($datarray['body']);
                if (x($ev, 'desc') && x($ev, 'start')) {
                    $ev['cid'] = $importer['id'];
                    $ev['uid'] = $importer['uid'];
                    $ev['uri'] = $item_id;
                    $ev['edited'] = $datarray['edited'];
                    $ev['private'] = $datarray['private'];
                    $r = q("SELECT * FROM `event` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['uid']));
                    if (count($r)) {
                        $ev['id'] = $r[0]['id'];
                    }
                    $xyz = event_store($ev);
                    continue;
                }
            }
            $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['importer_uid']));
            // Update content if 'updated' changes
            if (count($r)) {
                if (x($datarray, 'edited') !== false && datetime_convert('UTC', 'UTC', $datarray['edited']) !== $r[0]['edited']) {
                    // do not accept (ignore) an earlier edit than one we currently have.
                    if (datetime_convert('UTC', 'UTC', $datarray['edited']) < $r[0]['edited']) {
                        continue;
                    }
                    $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['tag']), dbesc(datetime_convert('UTC', 'UTC', $datarray['edited'])), dbesc($item_id), intval($importer['importer_uid']));
                    create_tags_from_itemuri($item_id, $importer['importer_uid']);
                }
                // update last-child if it changes
                $allow = $item->get_item_tags(NAMESPACE_DFRN, 'comment-allow');
                if ($allow && $allow[0]['data'] != $r[0]['last-child']) {
                    $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", intval($allow[0]['data']), dbesc(datetime_convert()), dbesc($item_id), intval($importer['importer_uid']));
                }
                continue;
            }
            // This is my contact on another system, but it's really me.
            // Turn this into a wall post.
            if ($importer['remote_self']) {
                $datarray['wall'] = 1;
            }
            $datarray['parent-uri'] = $item_id;
            $datarray['uid'] = $importer['importer_uid'];
            $datarray['contact-id'] = $importer['id'];
            if (!link_compare($datarray['owner-link'], $importer['url'])) {
                // The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery,
                // but otherwise there's a possible data mixup on the sender's system.
                // the tgroup delivery code called from item_store will correct it if it's a forum,
                // but we're going to unconditionally correct it here so that the post will always be owned by our contact.
                logger('local_delivery: Correcting item owner.', LOGGER_DEBUG);
                $datarray['owner-name'] = $importer['senderName'];
                $datarray['owner-link'] = $importer['url'];
                $datarray['owner-avatar'] = $importer['thumb'];
            }
            if ($importer['rel'] == CONTACT_IS_FOLLOWER && !tgroup_check($importer['importer_uid'], $datarray)) {
                continue;
            }
            $posted_id = item_store($datarray);
            if (stristr($datarray['verb'], ACTIVITY_POKE)) {
                $verb = urldecode(substr($datarray['verb'], strpos($datarray['verb'], '#') + 1));
                if (!$verb) {
                    continue;
                }
                $xo = parse_xml_string($datarray['object'], false);
                if ($xo->type == ACTIVITY_OBJ_PERSON && $xo->id) {
                    // somebody was poked/prodded. Was it me?
                    $links = parse_xml_string("<links>" . unxmlify($xo->link) . "</links>", false);
                    foreach ($links->link as $l) {
                        $atts = $l->attributes();
                        switch ($atts['rel']) {
                            case "alternate":
                                $Blink = $atts['href'];
                                break;
                            default:
                                break;
                        }
                    }
                    if ($Blink && link_compare($Blink, $a->get_baseurl() . '/profile/' . $importer['nickname'])) {
                        // send a notification
                        require_once 'include/enotify.php';
                        notification(array('type' => NOTIFY_POKE, 'notify_flags' => $importer['notify-flags'], 'language' => $importer['language'], 'to_name' => $importer['username'], 'to_email' => $importer['email'], 'uid' => $importer['importer_uid'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $posted_id, 'source_name' => stripslashes($datarray['author-name']), 'source_link' => $datarray['author-link'], 'source_photo' => link_compare($datarray['author-link'], $importer['url']) ? $importer['thumb'] : $datarray['author-avatar'], 'verb' => $datarray['verb'], 'otype' => 'person', 'activity' => $verb));
                    }
                }
            }
            continue;
        }
    }
    return 0;
    // NOTREACHED
}
Example #10
0
function dfrn_confirm_post(&$a)
{
    if ($a->argc > 1) {
        $node = $a->argv[1];
    }
    if (x($_POST, 'source_url')) {
        // We are processing an external confirmation to an introduction created by our user.
        $public_key = $_POST['public_key'];
        $dfrn_id = $_POST['dfrn_id'];
        $source_url = $_POST['source_url'];
        $aes_key = $_POST['aes_key'];
        $duplex = $_POST['duplex'];
        $version_id = $_POST['dfrn_version'];
        // Find our user's account
        $r = q("SELECT * FROM `user` WHERE `nickname` = '%s' LIMIT 1", dbesc($node));
        if (!count($r)) {
            xml_status(3);
            // failure
            return;
            // NOTREACHED
        }
        $my_prvkey = $r[0]['prvkey'];
        $local_uid = $r[0]['uid'];
        // verify everything
        $decrypted_source_url = "";
        openssl_private_decrypt($source_url, $decrypted_source_url, $my_prvkey);
        $ret = q("SELECT * FROM `contact` WHERE `url` = '%s' LIMIT 1", dbesc($decrypted_source_url));
        if (!count($ret)) {
            // this is either a bogus confirmation or we deleted the original introduction.
            xml_status(3);
            return;
            // NOTREACHED
        }
        $relation = $ret[0]['rel'];
        // Decrypt all this stuff we just received
        $foreign_pubkey = $ret[0]['site-pubkey'];
        $dfrn_record = $ret[0]['id'];
        $decrypted_dfrn_id = "";
        openssl_public_decrypt($dfrn_id, $decrypted_dfrn_id, $foreign_pubkey);
        if (strlen($aes_key)) {
            $decrypted_aes_key = "";
            openssl_private_decrypt($aes_key, $decrypted_aes_key, $my_prvkey);
            $dfrn_pubkey = openssl_decrypt($public_key, 'AES-256-CBC', $decrypted_aes_key);
        } else {
            $dfrn_pubkey = $public_key;
        }
        $r = q("SELECT * FROM `contact` WHERE `dfrn-id` = '%s' LIMIT 1", dbesc($decrypted_dfrn_id), intval($local_uid));
        if (count($r)) {
            xml_status(1);
            // Birthday paradox - duplicate dfrn-id
            return;
            // NOTREACHED
        }
        $r = q("UPDATE `contact` SET `dfrn-id` = '%s', `pubkey` = '%s' WHERE `id` = %d LIMIT 1", dbesc($decrypted_dfrn_id), dbesc($dfrn_pubkey), intval($dfrn_record));
        if ($r) {
            // We're good but now we have to scrape the profile photo and send notifications.
            require_once "Photo.php";
            $photo_failure = false;
            $r = q("SELECT `photo` FROM `contact` WHERE `id` = %d LIMIT 1", intval($dfrn_record));
            if (count($r)) {
                $filename = basename($r[0]['photo']);
                $img_str = fetch_url($r[0]['photo'], true);
                $img = new Photo($img_str);
                if ($img) {
                    $img->scaleImageSquare(175);
                    $hash = hash('md5', uniqid(mt_rand(), true));
                    $r = $img->store($dfrn_record, $hash, $filename, t('Contact Photos'), 4);
                    if ($r === false) {
                        $photo_failure = true;
                    }
                    $img->scaleImage(80);
                    $r = $img->store($dfrn_record, $hash, $filename, t('Contact Photos'), 5);
                    if ($r === false) {
                        $photo_failure = true;
                    }
                    $photo = $a->get_baseurl() . '/photo/' . $hash . '-4.jpg';
                    $thumb = $a->get_baseurl() . '/photo/' . $hash . '-5.jpg';
                } else {
                    $photo_failure = true;
                }
            } else {
                $photo_failure = true;
            }
            if ($photo_failure) {
                $photo = $a->get_baseurl() . '/images/default-profile.jpg';
                $thumb = $a->get_baseurl() . '/images/default-profile-sm.jpg';
            }
            $new_relation = DIRECTION_OUT;
            if ($relation == DIRECTION_IN || $duplex) {
                $new_relation = DIRECTION_BOTH;
            }
            $r = q("UPDATE `contact` SET \n\t\t\t\t`photo` = '%s',\n\t\t\t\t`thumb` = '%s',\n\t\t\t\t`rel` = %d,\n\t\t\t\t`name-date` = '%s',\n\t\t\t\t`uri-date` = '%s',\n\t\t\t\t`avatar-date` = '%s',\n\t\t\t\t`blocked` = 0,\n\t\t\t\t`pending` = 0,\n\t\t\t\t`duplex` = %d\n\t\t\t\t`network` = 'dfrn' WHERE `id` = %d LIMIT 1\n\t\t\t", dbesc($photo), dbesc($thumb), intval($newrelation), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($duplex), intval($dfrn_record));
            if ($r === false) {
                notice(t("Unable to set contact photo info.") . EOL);
            }
            // Otherwise everything seems to have worked and we are almost done. Yay!
            // Send an email notification
            $r = q("SELECT * FROM `contact` LEFT JOIN `user` ON `user`.`uid` = 1\n\t\t\t\tWHERE `contact`.`id` = %d LIMIT 1", intval($dfrn_record));
            if (count($r) && $r[0]['notify-flags'] & NOTIFY_CONFIRM) {
                $tpl = file_get_contents('view/intro_complete_eml.tpl');
                $email_tpl = replace_macros($tpl, array('$sitename' => $a->config['sitename'], '$siteurl' => $a->get_baseurl(), '$username' => $r[0]['username'], '$email' => $r[0]['email'], '$fn' => $r[0]['name'], '$dfrn_url' => $r[0]['url']));
                $res = mail($r[0]['email'], t("Introduction accepted at ") . $a->config['sitename'], $email_tpl, 'From: ' . t('Administrator') . '@' . $_SERVER[SERVER_NAME]);
                if (!$res) {
                    notice(t("Email notification failed.") . EOL);
                }
            }
            xml_status(0);
            // Success
            return;
            // NOTREACHED
        } else {
            xml_status(2);
            // Hopefully temporary problem that can be retried.
        }
        return;
        // NOTREACHED
        ////////////////////// End of this scenario ///////////////////////////////////////////////
    } else {
        // We are processing a local confirmation initiated on this system by our user to an external introduction.
        $uid = get_uid();
        if (!$uid) {
            notice(t("Permission denied.") . EOL);
            return;
        }
        $dfrn_id = x($_POST, 'dfrn_id') ? notags(trim($_POST['dfrn_id'])) : "";
        $intro_id = intval($_POST['intro_id']);
        $duplex = intval($_POST['duplex']);
        $r = q("SELECT * FROM `contact` WHERE `issued-id` = '%s' LIMIT 1", dbesc($dfrn_id));
        if (!count($r)) {
            notice(t('Node does not exist.') . EOL);
            return;
        }
        $contact_id = $r[0]['id'];
        $relation = $r[0]['rel'];
        $site_pubkey = $r[0]['site-pubkey'];
        $dfrn_confirm = $r[0]['confirm'];
        $aes_allow = $r[0]['aes_allow'];
        $res = openssl_pkey_new(array('digest_alg' => 'whirlpool', 'private_key_bits' => 4096, 'encrypt_key' => false));
        $private_key = '';
        openssl_pkey_export($res, $private_key);
        $pubkey = openssl_pkey_get_details($res);
        $public_key = $pubkey["key"];
        $r = q("UPDATE `contact` SET `issued-pubkey` = '%s', `prvkey` = '%s' WHERE `id` = %d LIMIT 1", dbesc($public_key), dbesc($private_key), intval($contact_id));
        $params = array();
        $src_aes_key = random_string();
        $result = '';
        openssl_private_encrypt($dfrn_id, $result, $a->user['prvkey']);
        $params['dfrn_id'] = $result;
        $params['public_key'] = $public_key;
        openssl_public_encrypt($_SESSION['my_url'], $params['source_url'], $site_pubkey);
        if ($aes_allow && function_exists('openssl_encrypt')) {
            openssl_public_encrypt($src_aes_key, $params['aes_key'], $site_pubkey);
            $params['public_key'] = openssl_encrypt($public_key, 'AES-256-CBC', $src_aes_key);
        }
        $params['dfrn_version'] = '2.0';
        if ($duplex == 1) {
            $params['duplex'] = 1;
        }
        $res = post_url($dfrn_confirm, $params);
        // uncomment the following two lines and comment the following xml/status lines
        // to debug the remote confirmation section (when both confirmations
        // and responses originate on this system)
        // echo $res;
        // $status = 0;
        $xml = simplexml_load_string($res);
        $status = (int) $xml->status;
        switch ($status) {
            case 0:
                notice(t("Confirmation completed successfully") . EOL);
                break;
            case 1:
                // birthday paradox - generate new dfrn-id and fall through.
                $new_dfrn_id = random_string();
                $r = q("UPDATE contact SET `issued-id` = '%s' WHERE `id` = %d LIMIT 1", dbesc($new_dfrn_id), intval($contact_id));
            case 2:
                notice(t("Temporary failure. Please wait and try again.") . EOL);
                break;
            case 3:
                notice(t("Introduction failed or was revoked. Cannot complete.") . EOL);
                break;
        }
        if (($status == 0 || $status == 3) && $intro_id) {
            //delete the notification
            $r = q("DELETE FROM `intro` WHERE `id` = %d LIMIT 1", intval($intro_id));
        }
        if ($status != 0) {
            return;
        }
        require_once "Photo.php";
        $photo_failure = false;
        $r = q("SELECT `photo` FROM `contact` WHERE `id` = %d LIMIT 1", intval($contact_id));
        if (count($r)) {
            $filename = basename($r[0]['photo']);
            $img_str = fetch_url($r[0]['photo'], true);
            $img = new Photo($img_str);
            if ($img) {
                $img->scaleImageSquare(175);
                $hash = hash('md5', uniqid(mt_rand(), true));
                $r = $img->store($contact_id, $hash, $filename, t('Contact Photos'), 4);
                if ($r === false) {
                    $photo_failure = true;
                }
                $img->scaleImage(80);
                $r = $img->store($contact_id, $hash, $filename, t('Contact Photos'), 5);
                if ($r === false) {
                    $photo_failure = true;
                }
                $photo = $a->get_baseurl() . '/photo/' . $hash . '-4.jpg';
                $thumb = $a->get_baseurl() . '/photo/' . $hash . '-5.jpg';
            } else {
                $photo_failure = true;
            }
        } else {
            $photo_failure = true;
        }
        if ($photo_failure) {
            $photo = $a->get_baseurl() . '/images/default-profile.jpg';
            $thumb = $a->get_baseurl() . '/images/default-profile-sm.jpg';
        }
        $new_relation = DIRECTION_IN;
        if ($relation == DIRECTION_OUT || $duplex) {
            $new_relation = DIRECTION_BOTH;
        }
        $r = q("UPDATE `contact` SET \n\t\t\t`photo` = '%s', \n\t\t\t`thumb` = '%s', \n\t\t\t`rel` = %d, \n\t\t\t`name-date` = '%s', \n\t\t\t`uri-date` = '%s', \n\t\t\t`avatar-date` = '%s', \n\t\t\t`blocked` = 0, \n\t\t\t`pending` = 0, \n\t\t\t`duplex` = %d,\n\t\t\t`network` = 'dfrn' WHERE `id` = %d LIMIT 1\n\t\t", dbesc($photo), dbesc($thumb), intval($newrelation), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($duplex), intval($contact_id));
        if ($r === false) {
            notice(t('Unable to set contact photo.') . EOL);
        }
        goaway($a->get_baseurl() . '/contacts/' . intval($contact_id));
        return;
        //NOTREACHED
    }
    return;
}
Example #11
0
function photo_init(&$a)
{
    // To-Do:
    // - checking with realpath
    // - checking permissions
    /*
    	$cache = get_config('system','itemcache');
            if (($cache != '') and is_dir($cache)) {
    		$cachefile = $cache."/".$a->argc."-".$a->argv[1]."-".$a->argv[2]."-".$a->argv[3];
    		if (file_exists($cachefile)) {
    			$data = file_get_contents($cachefile);
    
    			if(function_exists('header_remove')) {
    				header_remove('Pragma');
    				header_remove('pragma');
    			}
    
    			header("Content-type: image/jpeg");
     			header("Expires: " . gmdate("D, d M Y H:i:s", time() + (3600*24)) . " GMT");
    			header("Cache-Control: max-age=" . (3600*24));
    			echo $data;
    			killme();
    			// NOTREACHED
    		}
    	}*/
    $prvcachecontrol = false;
    switch ($a->argc) {
        case 4:
            $person = $a->argv[3];
            $customres = intval($a->argv[2]);
            $type = $a->argv[1];
            break;
        case 3:
            $person = $a->argv[2];
            $type = $a->argv[1];
            break;
        case 2:
            $photo = $a->argv[1];
            break;
        case 1:
        default:
            killme();
            // NOTREACHED
    }
    $default = 'images/person-175.jpg';
    if (isset($type)) {
        /**
         * Profile photos
         */
        switch ($type) {
            case 'profile':
            case 'custom':
                $resolution = 4;
                break;
            case 'micro':
                $resolution = 6;
                $default = 'images/person-48.jpg';
                break;
            case 'avatar':
            default:
                $resolution = 5;
                $default = 'images/person-80.jpg';
                break;
        }
        $uid = str_replace('.jpg', '', $person);
        $r = q("SELECT * FROM `photo` WHERE `scale` = %d AND `uid` = %d AND `profile` = 1 LIMIT 1", intval($resolution), intval($uid));
        if (count($r)) {
            $data = $r[0]['data'];
        }
        if (!isset($data)) {
            $data = file_get_contents($default);
        }
    } else {
        /**
         * Other photos
         */
        $resolution = 0;
        $photo = str_replace('.jpg', '', $photo);
        if (substr($photo, -2, 1) == '-') {
            $resolution = intval(substr($photo, -1, 1));
            $photo = substr($photo, 0, -2);
        }
        $r = q("SELECT `uid` FROM `photo` WHERE `resource-id` = '%s' AND `scale` = %d LIMIT 1", dbesc($photo), intval($resolution));
        if (count($r)) {
            $sql_extra = permissions_sql($r[0]['uid']);
            // Now we'll see if we can access the photo
            $r = q("SELECT * FROM `photo` WHERE `resource-id` = '%s' AND `scale` = %d {$sql_extra} LIMIT 1", dbesc($photo), intval($resolution));
            if (count($r)) {
                $data = $r[0]['data'];
            } else {
                // Does the picture exist? It may be a remote person with no credentials,
                // but who should otherwise be able to view it. Show a default image to let
                // them know permissions was denied. It may be possible to view the image
                // through an authenticated profile visit.
                // There won't be many completely unauthorised people seeing this because
                // they won't have the photo link, so there's a reasonable chance that the person
                // might be able to obtain permission to view it.
                $r = q("SELECT * FROM `photo` WHERE `resource-id` = '%s' AND `scale` = %d LIMIT 1", dbesc($photo), intval($resolution));
                if (count($r)) {
                    $data = file_get_contents('images/nosign.jpg');
                    $prvcachecontrol = true;
                }
            }
        }
    }
    if (!isset($data)) {
        if (isset($resolution)) {
            switch ($resolution) {
                case 4:
                    $data = file_get_contents('images/person-175.jpg');
                    break;
                case 5:
                    $data = file_get_contents('images/person-80.jpg');
                    break;
                case 6:
                    $data = file_get_contents('images/person-48.jpg');
                    break;
                default:
                    killme();
                    // NOTREACHED
                    break;
            }
        }
    }
    if (isset($customres) && $customres > 0 && $customres < 500) {
        require_once 'include/Photo.php';
        $ph = new Photo($data);
        if ($ph->is_valid()) {
            $ph->scaleImageSquare($customres);
            $data = $ph->imageString();
        }
    }
    // Writing in cachefile
    if (isset($cachefile) && $cachefile != '') {
        file_put_contents($cachefile, $data);
    }
    if (function_exists('header_remove')) {
        header_remove('Pragma');
        header_remove('pragma');
    }
    header("Content-type: image/jpeg");
    if ($prvcachecontrol) {
        // it is a private photo that they have no permission to view.
        // tell the browser not to cache it, in case they authenticate
        // and subsequently have permission to see it
        header("Cache-Control: no-store, no-cache, must-revalidate");
    } else {
        header("Expires: " . gmdate("D, d M Y H:i:s", time() + 3600 * 24) . " GMT");
        header("Cache-Control: max-age=" . 3600 * 24);
    }
    echo $data;
    killme();
    // NOTREACHED
}
Example #12
0
function run_submit($url)
{
    global $a;
    if (!strlen($url)) {
        return false;
    }
    logger('Updating: ' . $url);
    //First run a notice script for the site it is hosted on.
    $site_health = notice_site($url, true);
    $submit_start = microtime(true);
    $nurl = str_replace(array('https:', '//www.'), array('http:', '//'), $url);
    $profile_exists = false;
    $r = q("SELECT * FROM `profile` WHERE ( `homepage` = '%s' OR `nurl` = '%s' )", dbesc($url), dbesc($nurl));
    if (count($r)) {
        $profile_exists = true;
        $profile_id = $r[0]['id'];
    }
    //Remove duplicates.
    if (count($r) > 1) {
        for ($i = 1; $i < count($r); $i++) {
            logger('Removed duplicate profile ' . intval($r[$i]['id']));
            q("DELETE FROM `photo` WHERE `profile-id` = %d LIMIT 1", intval($r[$i]['id']));
            q("DELETE FROM `profile` WHERE `id` = %d LIMIT 1", intval($r[$i]['id']));
        }
    }
    require_once 'Scrape.php';
    //Skip the scrape? :D
    $noscrape = $site_health && $site_health['no_scrape_url'];
    if ($noscrape) {
        //Find out who to look up.
        $which = str_replace($site_health['base_url'], '', $url);
        $noscrape = preg_match('~/profile/([^/]+)~', $which, $matches) === 1;
        //If that did not fail...
        if ($noscrape) {
            $parms = noscrape_dfrn($site_health['no_scrape_url'] . '/' . $matches[1]);
            $noscrape = !!$parms;
            //If the result was false, do a scrape after all.
        }
    }
    if (!$noscrape) {
        $parms = scrape_dfrn($url);
    }
    //Empty result is due to an offline site.
    if (!count($parms)) {
        //For large sites this could lower the health too quickly, so don't track health.
        //But for sites that are already in bad status. Do a cleanup now.
        if ($profile_exists && $site_health['health_score'] < $a->config['maintenance']['remove_profile_health_threshold']) {
            logger('Nuked bad health record.');
            nuke_record($url);
        }
        return false;
    } elseif ($parms['explicit-hide'] && $profile_exists) {
        logger('User opted out of the directory.');
        nuke_record($url);
        return true;
        //This is a good update.
    } elseif (validate_dfrn($parms)) {
        return false;
    }
    if (x($parms, 'hide') || !x($parms, 'fn') && x($parms, 'photo')) {
        if ($profile_exists) {
            nuke_record($url);
        }
        return true;
        //This is a good update.
    }
    $photo = $parms['photo'];
    dbesc_array($parms);
    if (x($parms, 'comm')) {
        $parms['comm'] = intval($parms['comm']);
    }
    if ($profile_exists) {
        $r = q("UPDATE `profile` SET \n\t\t\t`name` = '%s', \n\t\t\t`pdesc` = '%s',\n\t\t\t`locality` = '%s', \n\t\t\t`region` = '%s', \n\t\t\t`postal-code` = '%s', \n\t\t\t`country-name` = '%s', \n\t\t\t`gender` = '%s', \n\t\t\t`marital` = '%s', \n\t\t\t`homepage` = '%s',\n\t\t\t`nurl` = '%s',\n\t\t\t`comm` = %d,\n\t\t\t`tags` = '%s',\n\t\t\t`updated` = '%s' \n\t\t\tWHERE `id` = %d LIMIT 1", $parms['fn'], $parms['pdesc'], $parms['locality'], $parms['region'], $parms['postal-code'], $parms['country-name'], $parms['gender'], $parms['marital'], dbesc($url), dbesc($nurl), intval($parms['comm']), $parms['tags'], dbesc(datetime_convert()), intval($profile_id));
        logger('Update returns: ' . $r);
    } else {
        $r = q("INSERT INTO `profile` ( `name`, `pdesc`, `locality`, `region`, `postal-code`, `country-name`, `gender`, `marital`, `homepage`, `nurl`, `comm`, `tags`, `created`, `updated` )\n\t\t\tVALUES ( '%s', '%s', '%s', '%s' , '%s', '%s', '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s' )", $parms['fn'], $parms['pdesc'], $parms['locality'], $parms['region'], $parms['postal-code'], $parms['country-name'], $parms['gender'], $parms['marital'], dbesc($url), dbesc($nurl), intval($parms['comm']), $parms['tags'], dbesc(datetime_convert()), dbesc(datetime_convert()));
        logger('Insert returns: ' . $r);
        $r = q("SELECT `id` FROM `profile` WHERE ( `homepage` = '%s' or `nurl` = '%s' ) order by id asc", dbesc($url), dbesc($nurl));
        if (count($r)) {
            $profile_id = $r[count($r) - 1]['id'];
        }
        if (count($r) > 1) {
            q("DELETE FROM `photo` WHERE `profile-id` = %d LIMIT 1", intval($r[0]['id']));
            q("DELETE FROM `profile` WHERE `id` = %d LIMIT 1", intval($r[0]['id']));
        }
    }
    if ($parms['tags']) {
        $arr = explode(' ', $parms['tags']);
        if (count($arr)) {
            foreach ($arr as $t) {
                $t = strip_tags(trim($t));
                $t = substr($t, 0, 254);
                if (strlen($t)) {
                    $r = q("SELECT `id` FROM `tag` WHERE `term` = '%s' and `nurl` = '%s' LIMIT 1", dbesc($t), dbesc($nurl));
                    if (!count($r)) {
                        $r = q("INSERT INTO `tag` (`term`, `nurl`) VALUES ('%s', '%s') ", dbesc($t), dbesc($nurl));
                    }
                }
            }
        }
    }
    $submit_photo_start = microtime(true);
    require_once "Photo.php";
    $photo_failure = false;
    $status = false;
    if ($profile_id) {
        $img_str = fetch_url($photo, true);
        $img = new Photo($img_str);
        if ($img) {
            $img->scaleImageSquare(80);
            $r = $img->store($profile_id);
        }
        $r = q("UPDATE `profile` SET `photo` = '%s' WHERE `id` = %d LIMIT 1", dbesc($a->get_baseurl() . '/photo/' . $profile_id . '.jpg'), intval($profile_id));
        $status = true;
    } else {
        nuke_record($url);
        return false;
    }
    $submit_end = microtime(true);
    $photo_time = round(($submit_end - $submit_photo_start) * 1000);
    $time = round(($submit_end - $submit_start) * 1000);
    //Record the scrape speed in a scrapes table.
    if ($site_health && $status) {
        q("INSERT INTO `site-scrape` (`site_health_id`, `dt_performed`, `request_time`, `scrape_time`, `photo_time`, `total_time`)" . "VALUES (%u, NOW(), %u, %u, %u, %u)", $site_health['id'], $parms['_timings']['fetch'], $parms['_timings']['scrape'], $photo_time, $time);
    }
    return $status;
}
Example #13
0
function photo_init(&$a)
{
    global $_SERVER;
    $prvcachecontrol = false;
    $file = "";
    switch ($a->argc) {
        case 4:
            $person = $a->argv[3];
            $customres = intval($a->argv[2]);
            $type = $a->argv[1];
            break;
        case 3:
            $person = $a->argv[2];
            $type = $a->argv[1];
            break;
        case 2:
            $photo = $a->argv[1];
            $file = $photo;
            break;
        case 1:
        default:
            killme();
            // NOTREACHED
    }
    //	strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= filemtime($localFileName)) {
    if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
        header('HTTP/1.1 304 Not Modified');
        header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT");
        header('Etag: ' . $_SERVER['HTTP_IF_NONE_MATCH']);
        header("Expires: " . gmdate("D, d M Y H:i:s", time() + 31536000) . " GMT");
        header("Cache-Control: max-age=31536000");
        if (function_exists('header_remove')) {
            header_remove('Last-Modified');
            header_remove('Expires');
            header_remove('Cache-Control');
        }
        exit;
    }
    $default = 'images/person-175.jpg';
    if (isset($type)) {
        /**
         * Profile photos
         */
        switch ($type) {
            case 'profile':
            case 'custom':
                $resolution = 4;
                break;
            case 'micro':
                $resolution = 6;
                $default = 'images/person-48.jpg';
                break;
            case 'avatar':
            default:
                $resolution = 5;
                $default = 'images/person-80.jpg';
                break;
        }
        $uid = str_replace(array('.jpg', '.png'), array('', ''), $person);
        $r = q("SELECT * FROM `photo` WHERE `scale` = %d AND `uid` = %d AND `profile` = 1 LIMIT 1", intval($resolution), intval($uid));
        if (count($r)) {
            $data = $r[0]['data'];
            $mimetype = $r[0]['type'];
        }
        if (!isset($data)) {
            $data = file_get_contents($default);
            $mimetype = 'image/jpeg';
        }
    } else {
        /**
         * Other photos
         */
        $resolution = 0;
        foreach (Photo::supportedTypes() as $m => $e) {
            $photo = str_replace(".{$e}", '', $photo);
        }
        if (substr($photo, -2, 1) == '-') {
            $resolution = intval(substr($photo, -1, 1));
            $photo = substr($photo, 0, -2);
        }
        $r = q("SELECT `uid` FROM `photo` WHERE `resource-id` = '%s' AND `scale` = %d LIMIT 1", dbesc($photo), intval($resolution));
        if (count($r)) {
            $sql_extra = permissions_sql($r[0]['uid']);
            // Now we'll see if we can access the photo
            $r = q("SELECT * FROM `photo` WHERE `resource-id` = '%s' AND `scale` = %d {$sql_extra} LIMIT 1", dbesc($photo), intval($resolution));
            $public = $r[0]['allow_cid'] == '' and $r[0]['allow_gid'] == '' and $r[0]['deny_cid'] == '' and $r[0]['deny_gid'] == '';
            if (count($r)) {
                $data = $r[0]['data'];
                $mimetype = $r[0]['type'];
            } else {
                // Does the picture exist? It may be a remote person with no credentials,
                // but who should otherwise be able to view it. Show a default image to let
                // them know permissions was denied. It may be possible to view the image
                // through an authenticated profile visit.
                // There won't be many completely unauthorised people seeing this because
                // they won't have the photo link, so there's a reasonable chance that the person
                // might be able to obtain permission to view it.
                $r = q("SELECT * FROM `photo` WHERE `resource-id` = '%s' AND `scale` = %d LIMIT 1", dbesc($photo), intval($resolution));
                if (count($r)) {
                    $data = file_get_contents('images/nosign.jpg');
                    $mimetype = 'image/jpeg';
                    $prvcachecontrol = true;
                }
            }
        }
    }
    if (!isset($data)) {
        if (isset($resolution)) {
            switch ($resolution) {
                case 4:
                    $data = file_get_contents('images/person-175.jpg');
                    $mimetype = 'image/jpeg';
                    break;
                case 5:
                    $data = file_get_contents('images/person-80.jpg');
                    $mimetype = 'image/jpeg';
                    break;
                case 6:
                    $data = file_get_contents('images/person-48.jpg');
                    $mimetype = 'image/jpeg';
                    break;
                default:
                    killme();
                    // NOTREACHED
                    break;
            }
        }
    }
    // Resize only if its not a GIF
    if ($mime != "image/gif") {
        $ph = new Photo($data, $mimetype);
        if ($ph->is_valid()) {
            if (isset($customres) && $customres > 0 && $customres < 500) {
                $ph->scaleImageSquare($customres);
            }
            $data = $ph->imageString();
            $mimetype = $ph->getType();
        }
    }
    if (function_exists('header_remove')) {
        header_remove('Pragma');
        header_remove('pragma');
    }
    header("Content-type: " . $mimetype);
    if ($prvcachecontrol) {
        // it is a private photo that they have no permission to view.
        // tell the browser not to cache it, in case they authenticate
        // and subsequently have permission to see it
        header("Cache-Control: no-store, no-cache, must-revalidate");
    } else {
        header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT");
        header('Etag: "' . md5($data) . '"');
        header("Expires: " . gmdate("D, d M Y H:i:s", time() + 31536000) . " GMT");
        header("Cache-Control: max-age=31536000");
    }
    echo $data;
    // If the photo is public and there is an existing photo directory store the photo there
    if ($public and $file != "") {
        if (is_dir($_SERVER["DOCUMENT_ROOT"] . "/photo")) {
            file_put_contents($_SERVER["DOCUMENT_ROOT"] . "/photo/" . $file, $data);
        }
    }
    killme();
    // NOTREACHED
}