code:
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2012 StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'i:n:g:G:';
$longoptions = array('id=', 'nickname=', 'group=', 'group-id=');

$helptext = <<<END_OF_HELP
joingroup.php [options]

Adds a local user to a local group.

  -i --id       ID of user to add
  -n --nickname nickname of the user to add
  -g --group    nickname or alias of group
  -G --group-id ID of group

END_OF_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

try {
    $user = getUser();
    $lgroup = null;
    if (have_option('G', 'group-id')) {
        $gid = get_option_value('G', 'group-id');
        $lgroup = Local_group::getKV('group_id', $gid);
    } else if (have_option('g', 'group')) {
        $gnick = get_option_value('g', 'group');
        $lgroup = Local_group::getKV('nickname', $gnick);
    }
    if (!$lgroup instanceof Local_group) {
        throw new Exception("No such local group: $gnick");
    }
    $group = User_group::getKV('id', $lgroup->group_id);
    $user->joinGroup($group);
    print "OK\n";
} catch (Exception $e) {
    print $e->getMessage()."\n";
    exit(1);
}


code:
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2012 StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'i:n:g:G:';
$longoptions = array('id=', 'nickname=', 'group=', 'group-id=');

$helptext = <<<END_OF_HELP
leavegroup.php [options]

Removes a local user from a local group.

  -i --id       ID of user to remove
  -n --nickname nickname of the user to remove
  -g --group    nickname or alias of group
  -G --group-id ID of group

END_OF_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

try {
    $user = getUser();
    $lgroup = null;
    if (have_option('G', 'group-id')) {
        $gid = get_option_value('G', 'group-id');
        $lgroup = Local_group::getKV('group_id', $gid);
    } else if (have_option('g', 'group')) {
        $gnick = get_option_value('g', 'group');
        $lgroup = Local_group::getKV('nickname', $gnick);
    }
    if (!$lgroup instanceof Local_group) {
        throw new Exception("No such local group: $gnick");
    }
    $group = User_group::getKV('id', $lgroup->group_id);
    $user->leaveGroup($group);
    print "OK\n";
} catch (Exception $e) {
    print $e->getMessage()."\n";
    exit(1);
}

repo_name: RMichael/gnu

license: mit


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$helptext = <<<END_OF_HELP
Script for converting mail messages into notices. Takes message body
as STDIN.

END_OF_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';
require_once INSTALLDIR.'/lib/mailhandler.php';

if (common_config('emailpost', 'enabled')) {
    $mh = new MailHandler();
    $mh->handle_message(file_get_contents('php://stdin'));
}


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2010, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// Abort if called from a web server

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

require_once INSTALLDIR.'/scripts/commandline.inc';

$base = INSTALLDIR;
$encBase = escapeshellarg($base);

$ver = GNUSOCIAL_VERSION;

// @fixme hack
if (preg_match('/^(\d+)\.(\d+)\.(\d+)/', $ver, $matches)) {
    list(, $a, $b, $c) = $matches;
    if ($c > '0') {
        $cprime = $c - 1;
        $prev = "$a.$b.$cprime";
    } else {
        die("This is a .0 release; you need to provide a thingy.\n");
    }
}

$tag = $ver;
$prefix = "statusnet-$tag";
$target = "$prefix.tar.gz";

$cmd = <<<END
(cd $encBase && git archive --prefix=$prefix/ $tag | gzip > /tmp/$target) && \
(cd /tmp && tar zxf $target && cd $prefix && make) && \
(cd $encBase && git log --oneline {$prev}..{$tag} > /tmp/$prefix/Changelog) && \
(cd /tmp && tar zcf $target $prefix) && \
(cd /tmp && rm -rf $prefix) && \
(mv /tmp/$target .)
END;

echo $cmd;
echo "\n";


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'g:n:';
$longoptions = array('nickname=', 'group=');

$helptext = <<<END_OF_MAKEGROUPADMIN_HELP
makegroupadmin.php [options]
makes a user the admin of a group

  -g --group    group to add an admin to
  -n --nickname nickname of the new admin

END_OF_MAKEGROUPADMIN_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

$nickname = get_option_value('n', 'nickname');
$groupname = get_option_value('g', 'group');

if (empty($nickname) || empty($groupname)) {
    print "Must provide a nickname and group.\n";
    exit(1);
}

try {

    $user = User::getKV('nickname', $nickname);

    if (empty($user)) {
        throw new Exception("No user named '$nickname'.");
    }

    $group = User_group::getKV('nickname', $groupname);

    if (empty($group)) {
        throw new Exception("No group named '$groupname'.");
    }

    $member = Group_member::pkeyGet(array('group_id' => $group->id,
                                          'profile_id' => $user->id));

    if (empty($member)) {
        $member = new Group_member();

        $member->group_id   = $group->id;
        $member->profile_id = $user->id;
        $member->created    = common_sql_now();

        if (!$member->insert()) {
            throw new Exception("Can't add '$nickname' to '$groupname'.");
        }
    }

    if ($member->is_admin) {
        throw new Exception("'$nickname' is already an admin of '$groupname'.");
    }

    $orig = clone($member);

    $member->is_admin = 1;

    if (!$member->update($orig)) {
        throw new Exception("Can't make '$nickname' admin of '$groupname'.");
    }

} catch (Exception $e) {
    print $e->getMessage() . "\n";
    exit(1);
}


code:
#!/bin/bash

# live fast! die young!

set -e

# move_status_network.sh nickname newserver

export nickname="$1"
export newdbhost="$2"

source /etc/statusnet/setup.cfg

function set_maintenance_mode()
{
    local nickname=$1;

    php $PHPBASE/scripts/settag.php $nickname maintenancemode;
}

function get_current_db_info()
{
    local nickname=$1;

    #FIXME I couldn't make this work better

    export dbhost=`mysql -NB -h $SITEDBHOSTNAME -u $ADMIN --password=$ADMINPASS -e "SELECT dbhost FROM status_network WHERE nickname = '$nickname'" $SITEDB`
    export dbuser=`mysql -NB -h $SITEDBHOSTNAME -u $ADMIN --password=$ADMINPASS -e "SELECT dbuser FROM status_network WHERE nickname = '$nickname'" $SITEDB`
    export dbpass=`mysql -NB -h $SITEDBHOSTNAME -u $ADMIN --password=$ADMINPASS -e "SELECT dbpass FROM status_network WHERE nickname = '$nickname'" $SITEDB`
    export dbname=`mysql -NB -h $SITEDBHOSTNAME -u $ADMIN --password=$ADMINPASS -e "SELECT dbname FROM status_network WHERE nickname = '$nickname'" $SITEDB`
}

function create_empty_db()
{
    local newdbhost=$1;
    local dbuser=$2;
    local dbpass=$3;
    local dbname=$4;

    mysqladmin -h $newdbhost -u $ADMIN --password=$ADMINPASS create $dbname;

    mysql -h $newdbhost -u $ADMIN --password=$ADMINPASS -e "GRANT ALL ON $dbname.* TO '$dbuser'@'localhost' IDENTIFIED BY '$dbpass';" $dbname;
    mysql -h $newdbhost -u $ADMIN --password=$ADMINPASS -e "GRANT ALL ON $dbname.* TO '$dbuser'@'%' IDENTIFIED BY '$dbpass';" $dbname;
}

function transfer_data()
{
    local dbhost=$1;
    local newdbhost=$2;
    local dbuser=$3;
    local dbpass=$4;
    local dbname=$5;
    local dumpfile=`mktemp`;

    mysqldump -h $dbhost -u $ADMIN --password=$ADMINPASS $dbname > $dumpfile;
    mysql -h $newdbhost -u $ADMIN --password=$ADMINPASS $dbname < $dumpfile;
    rm $dumpfile;
}

function update_routing_table()
{
    local nickname=$1;
    local newdbhost=$2;

    mysql -h $SITEDBHOSTNAME -u $ADMIN --password=$ADMINPASS -e "UPDATE status_network set dbhost = '$newdbhost' where nickname = '$nickname'" $SITEDB
}

function flush_site()
{
    local nickname=$1;

    php $PHPBASE/scripts/flushsite.php -s$nickname.$WILDCARD
}

function unset_maintenance_mode()
{
    local nickname=$1;

    php $PHPBASE/scripts/settag.php -d $nickname maintenancemode;
}

echo -n Setting maintenance mode on $nickname...
set_maintenance_mode $nickname
echo DONE.
echo -n Getting current database info...
get_current_db_info $nickname
echo DONE.
echo -n Creating empty $dbname database on server $newdbhost...
create_empty_db $newdbhost $dbuser $dbpass $dbname
echo DONE
echo -n Copying $dbname database from $dbhost to $newdbhost...
transfer_data $dbhost $newdbhost $dbuser $dbpass $dbname
echo DONE
echo -n Updating the routing table for $nickname to use $dbname on $newdbhost...
update_routing_table $nickname $newdbhost
echo DONE
echo -n Flushing $nickname site from cache...
flush_site $nickname
echo DONE
echo -n Turning off maintenance mode on $nickname...
unset_maintenance_mode $nickname
echo DONE.


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2010 StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'i:n:r:w:y';
$longoptions = array('id=', 'nickname=', 'remote=', 'password=');

$helptext = <<<END_OF_MOVEUSER_HELP
moveuser.php [options]
Move a local user to a remote account.

  -i --id       ID of user to move
  -n --nickname nickname of the user to move
  -r --remote   Full ID of remote users
  -w --password Password of remote user
  -y --yes      do not wait for confirmation

Remote user identity must be a Webfinger (nickname@example.com) or
an HTTP or HTTPS URL (http://example.com/social/site/user/nickname).

END_OF_MOVEUSER_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

try {

    $user = getUser();

    $remote = get_option_value('r', 'remote');

    if (empty($remote)) {
        show_help();
        exit(1);
    }

    $password = get_option_value('w', 'password');

    if (!have_option('y', 'yes')) {
        print "WARNING: EXPERIMENTAL FEATURE! Moving accounts will delete data from the source site.\n";
        print "\n";
        print "About to PERMANENTLY move user '{$user->nickname}' to $remote. Are you sure? [y/N] ";
        $response = fgets(STDIN);
        if (strtolower(trim($response)) != 'y') {
            print "Aborting.\n";
            exit(0);
        }
    }

    $qm = QueueManager::get();

    $qm->enqueue(array($user, $remote, $password), 'acctmove');

} catch (Exception $e) {
    print $e->getMessage()."\n";
    exit(1);
}


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'i::yv';
$longoptions = array('id=', 'yes', 'verbose');

$helptext = <<<END_OF_HELP
nukefile.php [options]
deletes a file and related notices from the database

  -i --id       ID of the file
  -v --verbose  Be verbose (print the contents of the notices deleted).

END_OF_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

if (have_option('i', 'id')) {
    $id = get_option_value('i', 'id');
    $file = File::getKV('id', $id);
    if (!$file instanceof File) {
        print "Can't find file with ID $id\n";
        exit(1);
    }
} else {
    print "You must provide a file ID.\n";
    exit(1);
}

$verbose = have_option('v', 'verbose');

if (!have_option('y', 'yes')) {
    try {
        $filename = $file->getFilename();
    } catch (Exception $e) {
        $filename = '(remote file or no filename)';
    }
    print "About to PERMANENTLY delete file ($filename) with id=={$file->id}) AND its related notices. Are you sure? [y/N] ";
    $response = fgets(STDIN);
    if (strtolower(trim($response)) != 'y') {
        print "Aborting.\n";
        exit(0);
    }
}

print "Finding notices...\n";
try {
    $ids = File_to_post::getNoticeIDsByFile($file);
    $notice = Notice::multiGet('id', $ids);
    while ($notice->fetch()) {
        print "Deleting notice {$notice->id}".($verbose ? ": $notice->content\n" : "\n");
        $notice->delete();
    }
} catch (NoResultException $e) {
    print "No notices found with this File attached.\n";
}
print "Deleting File object together with possibly locally stored copy.\n";
$file->delete();
print "DONE.\n";


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2010, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Sends control signals to running queue daemons.
 *
 * @author Brion Vibber <brion@status.net>
 * @package QueueHandler
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'ur';
$longoptions = array('update', 'restart', 'stop');

$helptext = <<<END_OF_QUEUECTL_HELP
Send broadcast events to control any running queue handlers.
(Currently for Stomp queues only.)

Events relating to current site (as selected with -s etc)
    -u --update       Announce new site or updated configuration. Running
                      daemons will start subscribing to any new queues needed
                      for this site.

Global events:
    -r --restart      Graceful restart of all threads
       --stop         Graceful shutdown of all threads

END_OF_QUEUECTL_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

function doSendControl($message, $event, $param='')
{
    print $message;
    $qm = QueueManager::get();
    if ($qm->sendControlSignal($event, $param)) {
        print " sent.\n";
    } else {
        print " FAILED.\n";
    }
}

$actions = 0;

if (have_option('u') || have_option('--update')) {
    $nickname = common_config('site', 'nickname');
    doSendControl("Sending site update signal to queue daemons for $nickname",
                  "update", $nickname);
    $actions++;
}

if (have_option('r') || have_option('--restart')) {
    doSendControl("Sending graceful restart signal to queue daemons...",
                  "restart");
    $actions++;
}

if (have_option('--stop')) {
    doSendControl("Sending graceful shutdown signal to queue daemons...",
                  "shutdown");
    $actions++;
}

if (!$actions) {
    show_help();
}


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'fi:at:';
$longoptions = array('id=', 'foreground', 'all', 'threads=');

/**
 * Attempts to get a count of the processors available on the current system
 * to fan out multiple threads.
 *
 * Recognizes Linux and Mac OS X; others will return default of 1.
 *
 * @fixme move this to SpawningDaemon, but to get the default val for help
 *        text we seem to need it before loading infrastructure
 * @return intval
 */
function getProcessorCount()
{
    $cpus = 0;
    switch (PHP_OS) {
    case 'Linux':
        $cpuinfo = file('/proc/cpuinfo');
        foreach (file('/proc/cpuinfo') as $line) {
            if (preg_match('/^processor\s+:\s+(\d+)\s?$/', $line)) {
                $cpus++;
            }
        }
        break;
    case 'Darwin':
        $cpus = intval(shell_exec("/usr/sbin/sysctl -n hw.ncpu 2>/dev/null"));
        break;
    }
    if ($cpus) {
        return $cpus;
    }
    return 1;
}

$threads = getProcessorCount();
$helptext = <<<END_OF_QUEUE_HELP
Daemon script for running queued items.

    -i --id           Identity (default none)
    -f --foreground   Stay in the foreground (default background)
    -a --all          Handle queues for all local sites
                      (requires Stomp queue handler, status_network setup)
    -t --threads=<n>  Spawn <n> processing threads (default $threads)

END_OF_QUEUE_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

require_once(INSTALLDIR.'/lib/daemon.php');
require_once(INSTALLDIR.'/classes/Queue_item.php');
require_once(INSTALLDIR.'/classes/Notice.php');

/**
 * Queue handling daemon...
 *
 * The queue daemon by default launches in the background, at which point
 * it'll pass control to the configured QueueManager class to poll for updates.
 *
 * We can then pass individual items through the QueueHandler subclasses
 * they belong to.
 */
class QueueDaemon extends SpawningDaemon
{
    protected $allsites = false;

    function __construct($id=null, $daemonize=true, $threads=1, $allsites=false)
    {
        parent::__construct($id, $daemonize, $threads);
        $this->allsites = $allsites;
    }

    /**
     * Setup and start of run loop for this queue handler as a daemon.
     * Most of the heavy lifting is passed on to the QueueManager's service()
     * method, which passes control on to the QueueHandler's handle()
     * method for each item that comes in on the queue.
     *
     * @return boolean true on success, false on failure
     */
    function runThread()
    {
        $this->log(LOG_INFO, 'checking for queued notices');

        $master = new QueueMaster($this->get_id(), $this->processManager());
        $master->init($this->allsites);
        try {
            $master->service();
        } catch (Exception $e) {
            common_log(LOG_ERR, "Unhandled exception: " . $e->getMessage() . ' ' .
                str_replace("\n", " ", $e->getTraceAsString()));
            return self::EXIT_ERR;
        }

        $this->log(LOG_INFO, 'finished servicing the queue');

        $this->log(LOG_INFO, 'terminating normally');

        return $master->respawn ? self::EXIT_RESTART : self::EXIT_SHUTDOWN;
    }
}

class QueueMaster extends IoMaster
{
    protected $processManager;

    function __construct($id, $processManager)
    {
        parent::__construct($id);
        $this->processManager = $processManager;
    }

    /**
     * Initialize IoManagers which are appropriate to this instance.
     */
    function initManagers()
    {
        $managers = array();
        if (Event::handle('StartQueueDaemonIoManagers', array(&$managers))) {
            $qm = QueueManager::get();
            $qm->setActiveGroup('main');
            $managers[] = $qm;
            $managers[] = $this->processManager;
        }
        Event::handle('EndQueueDaemonIoManagers', array(&$managers));

        foreach ($managers as $manager) {
            $this->instantiate($manager);
        }
    }
}

if (have_option('i')) {
    $id = get_option_value('i');
} else if (have_option('--id')) {
    $id = get_option_value('--id');
} else if (count($args) > 0) {
    $id = $args[0];
} else {
    $id = null;
}

if (have_option('t')) {
    $threads = intval(get_option_value('t'));
} else if (have_option('--threads')) {
    $threads = intval(get_option_value('--threads'));
} else {
    //If there is no argument for number of threads
    //Try reading a config option for the number
    $threads = common_config('queue','threads');
}
if (!$threads) {
    $threads = getProcessorCount();
}

common_log(LOG_INFO, sprintf('Launching QueueDaemon background process with %1$d threads.', $threads));

$daemonize = !(have_option('f') || have_option('--foreground'));
$all = have_option('a') || have_option('--all');

$daemon = new QueueDaemon($id, $daemonize, $threads, $all);
$daemon->runOnce();


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'n:w:f:e:';
$longoptions = array('nickname=', 'password=', 'fullname=', 'email=');

$helptext = <<<END_OF_REGISTERUSER_HELP
registeruser.php [options]
registers a user in the database

  -n --nickname nickname of the new user
  -w --password password of the new user
  -f --fullname full name of the new user (optional)
  -e --email    email address of the new user (optional)

END_OF_REGISTERUSER_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

$nickname = get_option_value('n', 'nickname');
$password = get_option_value('w', 'password');
$fullname = get_option_value('f', 'fullname');

$email = get_option_value('e', 'email');

if (empty($nickname) || empty($password)) {
    print "Must provide a username and password.\n";
    exit(1);
}

try {

    $user = User::getKV('nickname', $nickname);

    if (!empty($user)) {
        throw new Exception("A user named '$nickname' already exists.");
    }

    $user = User::register(array('nickname' => $nickname,
                                 'password' => $password,
                                 'fullname' => $fullname));

    if (empty($user)) {
        throw new Exception("Can't register user '$nickname' with password '$password' and fullname '$fullname'.");
    }

    if (!empty($email)) {

        $orig = clone($user);

        $user->email = $email;

        // Throws exception on failure.
        $user->updateWithKeys($orig);
    }

} catch (Exception $e) {
    print $e->getMessage() . "\n";
    exit(1);
}


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'y';
$longoptions = array('yes');

$helptext = <<<END_OF_HELP
remove_duplicate_file_urls.php [options]
Remove duplicate URL entries in the file and file_redirection tables because they for some reason were not unique.

  -y --yes      do not wait for confirmation

END_OF_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

if (!have_option('y', 'yes')) {
    print "About to remove duplicate URL entries in file and file_redirection tables. Are you sure? [y/N] ";
    $response = fgets(STDIN);
    if (strtolower(trim($response)) != 'y') {
        print "Aborting.\n";
        exit(0);
    }
}

$file = new File();
$file->query('SELECT id, url, COUNT(*) AS c FROM file GROUP BY url HAVING c > 1');
print "\nFound {$file->N} URLs with duplicate entries in file table";
while ($file->fetch()) {
    // We've got a URL that is duplicated in the file table
    $dupfile = new File();
    $dupfile->url = $file->url;
    if ($dupfile->find(true)) {
        print "\nDeleting duplicate entries in file table for URL: {$file->url} [";
        // Leave one of the URLs in the database by using ->find(true)
        // and only deleting starting with this fetch.
        while($dupfile->fetch()) {
            print ".";
            $dupfile->delete();
        }
        print "]\n";
    } else {
        print "\nWarning! URL suddenly disappeared from database: {$file->url}\n";
    }
}

$file = new File_redirection();
$file->query('SELECT file_id, url, COUNT(*) AS c FROM file_redirection GROUP BY url HAVING c > 1');
print "\nFound {$file->N} URLs with duplicate entries in file_redirection table";
while ($file->fetch()) {
    // We've got a URL that is duplicated in the file_redirection table
    $dupfile = new File_redirection();
    $dupfile->url = $file->url;
    if ($dupfile->find(true)) {
        print "\nDeleting duplicate entries in file table for URL: {$file->url} [";
        // Leave one of the URLs in the database by using ->find(true)
        // and only deleting starting with this fetch.
        while($dupfile->fetch()) {
            print ".";
            $dupfile->delete();
        }
        print "]\n";
    } else {
        print "\nWarning! URL suddenly disappeared from database: {$file->url}\n";
    }
}
print "\nDONE.\n";


code:
#!/usr/bin/env php
<?php

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'e::ay';
$longoptions = array('email=', 'all', 'yes');

$self = basename($_SERVER['PHP_SELF']);

$helptext = <<<END_OF_HELP
{$self} [options]
resends confirmation email either for a specific email (if found) or for
all lingering confirmations.

NOTE: You probably want to do something like this to your database first so
only relatively fresh accounts get resent this:

    DELETE FROM confirm_address WHERE modified < DATE_SUB(NOW(), INTERVAL 1 month);

Options:

  -e --email        e-mail address to send for
  -a --all          send for all emails in confirm_address table
  -y --yes          skip interactive verification

END_OF_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

$all = false;
$ca = null;

if (have_option('e', 'email')) {
    $email = get_option_value('e', 'email');
    try {
        $ca = Confirm_address::getByAddress($email, 'email');
    } catch (NoResultException $e) {
        print sprintf("Can't find %s address %s in %s table.\n", $e->obj->address_type, $e->obj->address, $e->obj->tableName());
        exit(1);
    }
} elseif (have_option('a', 'all')) {
    $all = true;
    $ca = new Confirm_address();
    $ca->address_type = 'email';
    if (!$ca->find()) {
        print "confirm_address table contains no lingering email addresses\n";
        exit(0);
    }
} else {
    print "You must provide an email (or --all).\n";
    exit(1);
}

if (!have_option('y', 'yes')) {
    print "About to resend confirm_address email to {$ca->N} recipients. Are you sure? [y/N] ";
    $response = fgets(STDIN);
    if (strtolower(trim($response)) != 'y') {
        print "Aborting.\n";
        exit(0);
    }
}

function mailConfirmAddress(Confirm_address $ca)
{
    try {
        $user = User::getByID($ca->user_id);
        $profile = $user->getProfile();
        if ($profile->isSilenced()) {
            $ca->delete();
            return;
        }
        if ($user->email === $ca->address) {
            throw new AlreadyFulfilledException('User already has identical confirmed email address.');
        }
    } catch (AlreadyFulfilledException $e) {
        print "\n User already had verified email: "._ve($ca->address);
        $ca->delete();
    } catch (Exception $e) {
        print "\n Failed to get user with ID "._ve($user_id).', deleting confirm_address entry: '._ve($e->getMessage());
        $ca->delete();
        return;
    }
    mail_confirm_address($user, $ca->code, $user->getNickname(), $ca->address);
}

require_once(INSTALLDIR . '/lib/mail.php');

if (!$all) {
    mailConfirmAddress($ca);
} else {
    while ($ca->fetch()) {
        mailConfirmAddress($ca);
    }
}

print "\nDONE.\n";


code:
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2010 StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'i:n:f:';
$longoptions = array('id=', 'nickname=', 'file=');

$helptext = <<<END_OF_RESTOREUSER_HELP
restoreuser.php [options]
Restore a backed-up user file to the database. If
neither ID or name provided, will create a new user.

  -i --id       ID of user to export
  -n --nickname nickname of the user to export
  -f --file     file to read from (STDIN by default)

END_OF_RESTOREUSER_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

function getActivityStreamDocument()
{
    $filename = get_option_value('f', 'file');

    if (empty($filename)) {
        show_help();
        exit(1);
    }

    if (!file_exists($filename)) {
        throw new Exception("No such file '$filename'.");
    }

    if (!is_file($filename)) {
        throw new Exception("Not a regular file: '$filename'.");
    }

    if (!is_readable($filename)) {
        throw new Exception("File '$filename' not readable.");
    }

    // TRANS: Commandline script output. %s is the filename that contains a backup for a user.
    printfv(_("Getting backup from file '%s'.")."\n",$filename);

    $xml = file_get_contents($filename);

    return $xml;
}

try {
    try {
        $user = getUser();
    } catch (NoUserArgumentException $noae) {
        $user = null;
    }
    $xml = getActivityStreamDocument();
    $qm = QueueManager::get();
    $qm->enqueue(array($user, $xml, true), 'feedimp');
} catch (Exception $e) {
    print $e->getMessage()."\n";
    exit(1);
}


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'i:n:';
$longoptions = array('id=', 'nickname=', 'subject=');

$helptext = <<<END_OF_USEREMAIL_HELP
sendemail.php [options] < <message body>
Sends given email text to user.

  -i --id       id of the user to query
  -n --nickname nickname of the user to query
     --subject  mail subject line (required)

END_OF_USEREMAIL_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

if (have_option('i', 'id')) {
    $id = get_option_value('i', 'id');
    $user = User::getKV('id', $id);
    if (empty($user)) {
        print "Can't find user with ID $id\n";
        exit(1);
    }
} else if (have_option('n', 'nickname')) {
    $nickname = get_option_value('n', 'nickname');
    $user = User::getKV('nickname', $nickname);
    if (empty($user)) {
        print "Can't find user with nickname '$nickname'\n";
        exit(1);
    }
} else {
    print "You must provide a user by --id or --nickname\n";
    exit(1);
}

if (empty($user->email)) {
    // @fixme unconfirmed address?
    print "No email registered for user '$user->nickname'\n";
    exit(1);
}

if (!have_option('subject')) {
    echo "You must provide a subject line for the mail in --subject='...' param.\n";
    exit(1);
}
$subject = get_option_value('subject');

if (posix_isatty(STDIN)) {
    print "You must provide message input on stdin!\n";
    exit(1);
}
$body = file_get_contents('php://stdin');

print "Sending to $user->email...";
if (mail_to_user($user, $subject, $body)) {
    print " done\n";
} else {
    print " failed.\n";
    exit(1);
}


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$helptext = <<<END_OF_GC_HELP
sessiongc.php

Delete old sessions from the server

END_OF_GC_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

$maxlifetime = ini_get('session.gc_maxlifetime');

print "Deleting sessions older than $maxlifetime seconds.\n";

Session::gc($maxlifetime);


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'da';
$longoptions = array('delete', 'all');

$helptext = <<<END_OF_SETCONFIG_HELP
setconfig.php [options] [section] [setting] <value>
With three args, set the setting to the value.
With two args, just show the setting.
With -d, delete the setting.
With no args, lists all currently set values.

  [section]   section to use (required)
  [setting]   setting to use (required)
  <value>     value to set (optional)

  -d --delete delete the setting (no value)
  -a --all    list all configuration, not just the database values

END_OF_SETCONFIG_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

if (empty($args)) {
    if (have_option('a', 'all')) {
        foreach ($config as $section => $section_value) {
            foreach ($section_value as $setting => $value) {
                if (have_option('v', 'verbose') || !is_array($value)) {
                    // Don't print array's without the verbose flag
                    printf("%-20s %-20s %s\n", $section, $setting, var_export($value, true));
                }
            }
        }
    } else {
        $count = 0;
        $config = new Config();
        $config->find();
        while ($config->fetch()) {
            $count++;
            printf("%-20s %-20s %s\n", $config->section, $config->setting,
                   var_export($config->value, true));
        }
        if ($count == 0) {
            print "No configuration set in database for this site.\n";
        }
    }
    exit(0);
}

if (count($args) < 2 || count($args) > 3) {
    show_help();
    exit(1);
}

$section = $args[0];
$setting = $args[1];

if (count($args) == 3) {
    $value = $args[2];
} else {
    $value = null;
}

try {

    if (have_option('d', 'delete')) { // Delete
        if (count($args) != 2) {
            show_help();
            exit(1);
        }

        if (have_option('v', 'verbose')) {
            print "Deleting setting $section/$setting...";
        }

        $setting = Config::pkeyGet(array('section' => $section,
                                         'setting' => $setting));

        if (empty($setting)) {
            print "Not found.\n";
        } else {
            $result = $setting->delete();
            if ($result) {
                print "DONE.\n";
            } else {
                print "ERROR.\n";
            }
        }
    } else if (count($args) == 2) { // show
        if (have_option('v', 'verbose')) {
            print "$section/$setting = ";
        }
        $value = common_config($section, $setting);
        print "$value\n";
    } else { // set
        if (have_option('v', 'verbose')) {
            print "Setting $section/$setting...";
        }
        Config::save($section, $setting, $value);
        print "DONE.\n";
    }

} catch (Exception $e) {
    print $e->getMessage() . "\n";
    exit(1);
}


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$helptext = <<<END_OF_PASSWORD_HELP
setpassword.php <username> <password>

Sets the password of user with name <username> to <password>

END_OF_PASSWORD_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

if (count($args) < 2) {
    show_help();
}

$nickname = $args[0];
$password = $args[1];

if (mb_strlen($password) < 6) {
    print "Password must be 6 characters or more.\n";
    exit(1);
}

try {
    $user = User::getByNickname($nickname);
    $user->setPassword($password);
} catch (NoSuchUserException $e) {
    print $e->getMessage();
    exit(1);
}

print "Password for user '$nickname' updated.\n";


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'd';
$longoptions = array('delete');

$helptext = <<<END_OF_SETTAG_HELP
settag.php [options] <site> <tag>
Set the tag <tag> for site <site>.

With -d, delete the tag.

END_OF_SETTAG_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

if (count($args) < 1) {
    show_help();
    exit(1);
}

$nickname = $args[0];
$sn = Status_network::memGet('nickname', $nickname);

if (empty($sn)) {
    print "No such site ($nickname).\n";
    exit(-1);
}

$tags = $sn->getTags();

if (count($args) == 1) {
	print(implode(', ', $tags) . "\n");
	exit(0);
}
$tag = $args[1];
$i = array_search($tag, $tags);

if ($i !== false) {
    if (have_option('d', 'delete')) { // Delete
        unset($tags[$i]);

        $result = $sn->setTags($tags);
        if (!$result) {
            print "Couldn't update.\n";
            exit(-1);
        }
    } else {
        print "Already set.\n";
        exit(0);
    }
} else {
    if (have_option('d', 'delete')) { // Delete
        print "No such tag.\n";
        exit(0);
    } else {
        $tags[] = $tag;
        $result = $sn->setTags($tags);
        if (!$result) {
            print "Couldn't update.\n";
            exit(-1);
        }
    }
}


code:
# CONFIGURATION FILE for setup_status_network.sh

export DBHOST=localhost
export DBHOSTNAME=masterdb.example.net
export DBBASE=_example_net
export USERBASE=_example_net
export ADMIN=root
export ADMINPASS=yourpassword
export SITEDB=example_net_site
export AVATARBASE=/var/www/avatar.example.net
export BACKGROUNDBASE=/var/www/background.example.net
export FILEBASE=/var/www/file.example.net
export PWDGEN="pwgen 20"
export PHPBASE=/var/www/statusnet
export WILDCARD=example.net
export MAILTEMPLATE=/etc/statusnet/newsite-mail.txt
export MAILSUBJECT="Your new StatusNet site"
export POSTINSTALL=/etc/statusnet/morestuff.sh
export WEBUSER=www-data
export WEBGROUP=www-data
export TAGS=tag1,tag2,tag3


code:
#!/bin/bash

# live fast! die young!

set -e

source /etc/statusnet/setup.cfg

# setup_status_network.sh mysite 'My Site' '1user' 'owner@example.com' 'Firsty McLastname'

export nickname="$1"
export sitename="$2"
export tags="$3"
export email="$4"
export fullname="$5"
export siteplan="$6"

if [ "$siteplan" == '' ]; then
    siteplan='single-user'
fi

# Fixme: if this is changed later we need to update profile URLs
# for the created user.
export server="$nickname.$WILDCARD"

# End-user info
export userpass=`$PWDGEN`
export roles="administrator moderator owner"

# DB info
export password=`$PWDGEN`
export database=$nickname$DBBASE
export username=$nickname$USERBASE

# Create the db

mysqladmin -h $DBHOST -u $ADMIN --password=$ADMINPASS create $database

for f in statusnet.sql innodb.sql sms_carrier.sql foreign_services.sql notice_source.sql; do
    mysql -h $DBHOST -u $ADMIN --password=$ADMINPASS $database < ../db/$f;
done

mysql -h $DBHOST -u $ADMIN --password=$ADMINPASS $SITEDB << ENDOFCOMMANDS

GRANT ALL ON $database.* TO '$username'@'localhost' IDENTIFIED BY '$password';
GRANT ALL ON $database.* TO '$username'@'%' IDENTIFIED BY '$password';
INSERT INTO status_network (nickname, dbhost, dbuser, dbpass, dbname, sitename, created)
VALUES ('$nickname', '$DBHOSTNAME', '$username', '$password', '$database', '$sitename', now());

ENDOFCOMMANDS

for top in $AVATARBASE $FILEBASE $BACKGROUNDBASE; do
    mkdir $top/$nickname
    chmod a+w $top/$nickname
done

php $PHPBASE/scripts/checkschema.php -s"$server"

php $PHPBASE/scripts/settag.php -s"$server" "$nickname" "$tags"

php $PHPBASE/scripts/registeruser.php \
  -s"$server" \
  -n"$nickname" \
  -f"$fullname" \
  -w"$userpass" \
  -e"$email"

for role in $roles
do
  php $PHPBASE/scripts/userrole.php \
    -s"$server" \
    -n"$nickname" \
    -r"$role"
done

if [ -f "$MAILTEMPLATE" ]
then
    # fixme how safe is this? are sitenames sanitized?
    cat $MAILTEMPLATE | \
      sed "s/\$nickname/$nickname/" | \
      sed "s/\$sitename/$sitename/" | \
      sed "s/\$userpass/$userpass/" | \
      sed "s/\$siteplan/$siteplan/" | \
      php $PHPBASE/scripts/sendemail.php \
        -s"$server" \
        -n"$nickname" \
        --subject="$MAILSUBJECT"
else
    echo "No mail template, not sending email."
fi

if [ -f "$POSTINSTALL" ]
then
    echo "Running $POSTINSTALL ..."
    source "$POSTINSTALL"
fi


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = "t:l:v:k:";

$helptext = <<<ENDOFHELP
USAGE: showcache.php <args>
shows the cached object based on the args

  -t table     Table to look up
  -l column    Column to look up, default "id"
  -v value     Value to look up
  -k key       Key to look up; other args are ignored

ENDOFHELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

$karg = get_option_value('k');

if (!empty($karg)) {
    $k = Cache::key($karg);
} else {
    $table = get_option_value('t');
    if (empty($table)) {
        die("No table or key specified\n");
    }
    $column = get_option_value('l');
    if (empty($column)) {
        $column = 'id';
    }
    $value = get_option_value('v');

    $k = Memcached_DataObject::cacheKey($table, $column, $value);
}

print "Checking key '$k'...\n";

$c = Cache::instance();

if (empty($c)) {
    die("Can't initialize cache object!\n");
}

$obj = $c->get($k);

if (empty($obj)) {
    print "Empty.\n";
} else {
    var_dump($obj);
    print "\n";
}


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2010, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

require_once INSTALLDIR.'/scripts/commandline.inc';

foreach (StatusNet::getActivePlugins() as $plugin=>$args) {
    echo "$plugin: ";
    if (empty($args)) {
        echo "(no args)\n";
    } else {
        foreach ($args as $arg => $val) {
            echo "\n  $arg: ";
            var_export($val);
        }
        echo "\n";
    }
    echo "\n";
}


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$helptext = <<<END_OF_SHOWTABLE_HELP
showtable.php <tablename>
Shows the structure of a table

END_OF_SHOWTABLE_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

if (count($args) != 1) {
    show_help();
}

$name = $args[0];

$schema = Schema::get();

$td = $schema->getTableDef($name);

print_r($td);


code:
#!/bin/sh

# StatusNet - a distributed open-source microblogging tool

# Copyright (C) 2008, 2009, StatusNet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# This program tries to start the daemons for StatusNet.
# Note that the 'maildaemon' needs to run as a mail filter.

ARGSG=
ARGSD=

if [ $# -gt 0 ]; then
    ARGSG="$ARGSG -s$1"
    ID=`echo $1 | sed s/\\\\./_/g`
    ARGSD="$ARGSD -s$1 -i$ID"
fi

if [ $# -gt 1 ]; then
    ARGSD="$ARGSD -p$2"
    ARGSG="$ARGSG -p$2"
fi

DIR=`dirname $0`
DAEMONS=`php $DIR/getvaliddaemons.php $ARGSG`

for f in $DAEMONS; do

    echo "Starting $f..."
    php $f $ARGSD
    echo "DONE."

done


code:
#!/bin/bash

# StatusNet - a distributed open-source microblogging tool

# Copyright (C) 2008, 2009, StatusNet, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# This program tries to stop the daemons for GNU social that were
# previously started by startdaemons.sh

ARGSG=
SITENAME=
SITE=
ID="*"

# stopdaemons.sh [server [path]]

if [ $# -gt 0 ] ; then
	SITENAME="$1"
	SITE="-s$SITENAME"
	ID=`echo $SITENAME | sed s/\\\\./_/g`
	ARGSG="$ARGSG -s$1"
fi

if [ $# -gt 1 ]; then
	ARGSG="$ARGSG -p$2"
fi

SDIR=`dirname $0`
DIR=`php $SDIR/getpiddir.php $SITE`

DAEMONS=`php $SDIR/getvaliddaemons.php $ARGSG`

for f in $DAEMONS; do
    f=$(basename $f .php)

	FILES="$DIR/$f.$ID.pid"

	for ff in "$FILES" ; do

	 	PID=`cat $ff 2>/dev/null`
		if [ -n "$PID" ] ; then
		 	echo -n "Stopping $f ($PID)..."
			if kill -3 $PID 2>/dev/null ; then
				count=0
				while kill -0 $PID 2>/dev/null ;  do
					sleep 1
					count=$(($count + 1))
					if [ $count -gt 5 ]; then break; fi
				done
				if kill -9 $PID 2>/dev/null ; then
					echo "FORCIBLY TERMINATED"
				else
					echo "STOPPED CLEANLY"
				fi
			else
				echo "NOT FOUND"
			fi
		fi
		rm -f $ff
	done
done


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2009-2010, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'i::n::y';
$longoptions = array('id=', 'nickname=', 'yes', 'dry-run', 'all');

$helptext = <<<END_OF_HELP
strip_geo.php [options]
Removes geolocation info from the given user's notices.

  -i --id       ID of the user (may be a remote profile)
  -n --nickname nickname of the user
  -y --yes      do not wait for confirmation
     --dry-run  list affected notices without deleting
     --all      run over and decache all messages, even if they don't
                have geo data now (helps to fix cache bugs)

END_OF_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

if (have_option('i', 'id')) {
    $id = get_option_value('i', 'id');
    $profile = Profile::getKV('id', $id);
    if (empty($profile)) {
        print "Can't find local or remote profile with ID $id\n";
        exit(1);
    }
} else if (have_option('n', 'nickname')) {
    $nickname = get_option_value('n', 'nickname');
    $user = User::getKV('nickname', $nickname);
    if (empty($user)) {
        print "Can't find local user with nickname '$nickname'\n";
        exit(1);
    }
    $profile = $user->getProfile();
} else {
    print "You must provide either an ID or a nickname.\n\n";
    show_help();
    exit(1);
}

if (!have_option('y', 'yes') && !have_option('--dry-run')) {
    print "About to PERMANENTLY remove geolocation data from user '{$profile->nickname}' ({$profile->id})'s notices. Are you sure? [y/N] ";
    $response = fgets(STDIN);
    if (strtolower(trim($response)) != 'y') {
        print "Aborting.\n";
        exit(0);
    }
}

// @fixme for a very prolific poster this could be too many.
$notice = new Notice();
$notice->profile_id = $profile->id;
if (have_option('--all')) {
    print "Finding all notices by $profile->nickname...";
} else {
    print "Finding notices by $profile->nickname with geolocation data...";
    $notice->whereAdd("lat != ''");
}
$notice->find();

if ($notice->N) {
    print " $notice->N found.\n";
    while ($notice->fetch()) {
        print "notice id $notice->id ";
        if (have_option('v') || have_option('--verbose')) {
            print "({$notice->lat},{$notice->lon}) ";
            if ($notice->location_ns) {
                print "ns {$notice->location_ns} id {$notice->location_id} ";
            }
        }
        if (have_option('--dry-run')) {
            // sucka
            echo "(skipped)";
        } else {
            // note: setting fields to null and calling update() doesn't save the nulled fields
            $orig = clone($notice);
            $update = clone($notice);

            // In theory we could hit a chunk of notices at once in the UPDATE,
            // but we're going to have to decache them individually anyway and
            // it doesn't hurt to make sure we don't hold up replication with
            // what might be a very slow single UPDATE.
            $query = sprintf('UPDATE notice ' .
                             'SET lat=NULL,lon=NULL,location_ns=NULL,location_id=NULL ' .
                             'WHERE id=%d', $notice->id);
            $ok = $update->query($query);
            if ($ok) {
                // And now we decache him manually, as query() doesn't know what we're doing...
                $orig->decache();
                echo "(removed)";
            } else {
                echo "(unchanged?)";
            }
        }
        print "\n";
    }
} else {
    print " none found.\n";
}

print "DONE.\n";


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$helptext = <<<ENDOFHELP
uncache_users.php <idfile>

Uncache users listed in an ID file, default 'ids.txt'.

ENDOFHELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

$id_file = (count($args) > 1) ? $args[0] : 'ids.txt';

common_log(LOG_INFO, 'Updating user inboxes.');

$ids = file($id_file);

$memc = Cache::instance();

foreach ($ids as $id) {

	$user = User::getKV('id', $id);

	if (!$user) {
		common_log(LOG_WARNING, 'No such user: ' . $id);
		continue;
	}

    $user->decache();

    $memc->delete(Cache::key('user:notices_with_friends:'. $user->id));
    $memc->delete(Cache::key('user:notices_with_friends:'. $user->id . ';last'));
}


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// Abort if called from a web server
if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
    print "This script must be run from the command line\n";
    exit();
}

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

function update_core($dir, $domain)
{
    $old = getcwd();
    chdir($dir);
    passthru(<<<END
xgettext \
    --from-code=UTF-8 \
    --default-domain=$domain \
    --output=locale/$domain.pot \
    --language=PHP \
    --add-comments=TRANS \
    --keyword="_m:1,1t" \
    --keyword="_m:1c,2,2t" \
    --keyword="_m:1,2,3t" \
    --keyword="_m:1c,2,3,4t" \
    --keyword="pgettext:1c,2" \
    --keyword="npgettext:1c,2,3" \
    index.php \
    actions/*.php \
    classes/*.php \
    lib/*.php \
    scripts/*.php
END
);
    chdir($old);
}

function do_update_plugin($dir, $domain)
{
    $old = getcwd();
    chdir($dir);
    if (!file_exists('locale')) {
        mkdir('locale');
    }
    $files = get_plugin_sources(".");
    $cmd = <<<END
xgettext \
    --from-code=UTF-8 \
    --default-domain=$domain \
    --output=locale/$domain.pot \
    --language=PHP \
    --add-comments=TRANS \
    --keyword='' \
    --keyword="_m:1,1t" \
    --keyword="_m:1c,2,2t" \
    --keyword="_m:1,2,3t" \
    --keyword="_m:1c,2,3,4t" \

END;
    foreach ($files as $file) {
      $cmd .= ' ' . escapeshellarg($file);
    }
    passthru($cmd);
    chdir($old);
}

function get_plugins($dir)
{
    $plugins = array();
    $dirs = new DirectoryIterator("$dir/plugins");
    foreach ($dirs as $item) {
        if ($item->isDir() && !$item->isDot()) {
            $name = $item->getBasename();
            if (file_exists("$dir/plugins/$name/{$name}Plugin.php")) {
                $plugins[] = $name;
            }
        }
    }
    return $plugins;
}

function get_plugin_sources($dir)
{
    $files = array();

    $dirs = new RecursiveDirectoryIterator($dir);
    $iter = new RecursiveIteratorIterator($dirs);
    foreach ($iter as $pathname => $item) {
        if ($item->isFile() && preg_match('/\.php$/', $item->getBaseName())) {
            $files[] = $pathname;
        }
    }
    return $files;
}

function plugin_using_gettext($dir)
{
    $files = get_plugin_sources($dir);
    foreach ($files as $pathname) {
        // Check if the file is using our _m gettext wrapper
        $code = file_get_contents($pathname);
        if (preg_match('/\b_m\(/', $code)) {
            return true;
        }
    }

    return false;
}

function update_plugin($basedir, $name)
{
    $dir = "$basedir/plugins/$name";
    if (plugin_using_gettext($dir)) {
        do_update_plugin($dir, $name);
        return true;
    } else {
        return false;
    }
}

$args = $_SERVER['argv'];
array_shift($args);

$all = false;
$core = false;
$allplugins = false;
$plugins = array();
if (count($args) == 0) {
    $all = true;
}
foreach ($args as $arg) {
    if ($arg == '--all') {
        $all = true;
    } elseif ($arg == "--core") {
        $core = true;
    } elseif ($arg == "--plugins") {
        $allplugins = true;
    } elseif (substr($arg, 0, 9) == "--plugin=") {
        $plugins[] = substr($arg, 9);
    } elseif ($arg == '--help') {
        echo "options: --all --core --plugins --plugin=Foo\n\n";
        exit(0);
    }
}

if ($all || $core) {
    echo "core...";
    update_core(INSTALLDIR, 'statusnet');
    echo " ok\n";
}
if ($all || $allplugins) {
    $plugins = get_plugins(INSTALLDIR);
}
if ($plugins) {
    foreach ($plugins as $plugin) {
        echo "$plugin...";
        if (update_plugin(INSTALLDIR, $plugin)) {
            echo " ok\n";
        } else {
            echo " not localized\n";
        }
    }
}


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// Abort if called from a web server
if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
    print "This script must be run from the command line\n";
    exit();
}

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
define('GNUSOCIAL', true);
define('STATUSNET', true);  // compatibility

require_once(INSTALLDIR . '/lib/common.php');

// Master StatusNet .pot file location (created by update_pot.sh)
$statusnet_pot = INSTALLDIR . '/locale/statusnet.pot';

set_time_limit(60);

/* Languages to pull */
$languages = get_all_languages();

/* Update the languages */
// Language code conversion for translatewiki.net (these are MediaWiki codes)
$codeMap = array(
	'nb'    => 'no',
	'pt_BR' => 'pt-br',
	'zh_CN' => 'zh-hans',
	'zh_TW' => 'zh-hant'
);

$doneCodes = array();

foreach ($languages as $language) {
	$code = $language['lang'];

	// Skip export of source language
	// and duplicates
	if( $code == 'en' || $code == 'no' ) {
		continue;
	}

	// Do not export codes twice (happens for 'nb')
	if( in_array( $code, $doneCodes ) ) {
		continue;
	} else {
		$doneCodes[] = $code;
	}

	// Convert code if needed
	if( isset( $codeMap[$code] ) ) {
		$twnCode = $codeMap[$code];
	} else {
		$twnCode = str_replace('_', '-', strtolower($code)); // pt_BR -> pt-br
	}

    // Fetch updates from translatewiki.net...
    $file_url = 'http://translatewiki.net/w/i.php?' .
        http_build_query(array(
            'title' => 'Special:Translate',
            'task' => 'export-to-file',
            'group' => 'out-statusnet-core',
            'language' => $twnCode));

    $lcdir = INSTALLDIR . '/locale/' . $code;
    $msgdir = "$lcdir/LC_MESSAGES";
    $pofile = "$msgdir/statusnet.po";
    $mofile = "$msgdir/statusnet.mo";

    /* Check for an existing */
    if (!is_dir($msgdir)) {
        mkdir($lcdir);
        mkdir($msgdir);
        $existingSHA1 = '';
    } else {
        $existingSHA1 = file_exists($pofile) ? sha1_file($pofile) : '';
    }

    /* Get the remote one */
    $new_file = curl_get_file($file_url);

    if ($new_file === FALSE) {
        echo "Could not retrieve .po file for $code: $file_url\n";
        continue;
    }

    // Update if the local .po file is different to the one downloaded, or
    // if the .mo file is not present.
    if (sha1($new_file) != $existingSHA1 || !file_exists($mofile)) {
        echo "Updating ".$code."\n";
        file_put_contents($pofile, $new_file);
        // --backup=off is workaround for Mac OS X fail
        system(sprintf('msgmerge -U --backup=off %s %s', $pofile, $statusnet_pot));
        /* Do not rebuild/add .mo files by default
         * FIXME: should be made a command line parameter.
        system(sprintf('msgfmt -o %s %s', $mofile, $pofile));
         */
    } else {
        echo "Unchanged - ".$code."\n";
    }
}

echo "Finished\n";

function curl_get_file($url)
{
    $c = curl_init();
    curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($c, CURLOPT_URL, $url);
    $contents = curl_exec($c);
    curl_close($c);

    if (!empty($contents)) {
        return $contents;
    }

    return FALSE;
}


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'i:n:af';
$longoptions = array('id=', 'nickname=', 'all', 'force');

$helptext = <<<END_OF_UPDATELOCATION_HELP
updatelocation.php [options]
set the location for a profile

  -i --id       ID of user to update
  -n --nickname nickname of the user to update
  -f --force    force update even if user already has a location
  -a --all      update all

END_OF_UPDATELOCATION_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

try {
    $user = null;

    if (have_option('i', 'id')) {
        $id = get_option_value('i', 'id');
        $user = User::getKV('id', $id);
        if (empty($user)) {
            throw new Exception("Can't find user with id '$id'.");
        }
        updateLocation($user);
    } else if (have_option('n', 'nickname')) {
        $nickname = get_option_value('n', 'nickname');
        $user = User::getKV('nickname', $nickname);
        if (empty($user)) {
            throw new Exception("Can't find user with nickname '$nickname'");
        }
        updateLocation($user);
    } else if (have_option('a', 'all')) {
        $user = new User();
        if ($user->find()) {
            while ($user->fetch()) {
                updateLocation($user);
            }
        }
    } else {
        show_help();
        exit(1);
    }
} catch (Exception $e) {
    print $e->getMessage()."\n";
    exit(1);
}

function updateLocation($user)
{
    $profile = $user->getProfile();

    if (empty($profile)) {
        throw new Exception("User has no profile: " . $user->nickname);
    }

    if (empty($profile->location)) {
        if (have_option('v', 'verbose')) {
            print "No location string for '".$user->nickname."'\n";
        }
        return;
    }

    if (!empty($profile->location_id) && !have_option('f', 'force')) {
        if (have_option('v', 'verbose')) {
            print "Location ID already set for '".$user->nickname."'\n";
        }
        return;
    }

    $loc = Location::fromName($profile->location);

    if (empty($loc)) {
        if (have_option('v', 'verbose')) {
            print "No structured location for string '".$profile->location."' for user '".$user->nickname."'\n";
        }
        return;
    } else {
        $orig = clone($profile);

        $profile->lat         = $loc->lat;
        $profile->lon         = $loc->lon;
        $profile->location_id = $loc->location_id;
        $profile->location_ns = $loc->location_ns;

        $result = $profile->update($orig);

        if (!$result) {
            common_log_db_error($profile, 'UPDATE', __FILE__);
        }

        if (!have_option('q', 'quiet')) {
            print "Location ID " . $profile->location_id . " set for user " . $user->nickname . "\n";
        }
    }

    $profile->free();
    unset($loc);
    unset($profile);

    return;
}


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2008-2011, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = '';
$longoptions = array();

$helptext = <<<END_OF_UPDATEURLS_HELP
updateurls.php [options]
update stored URLs in the system

END_OF_UPDATEURLS_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

function main()
{
    updateUserUrls();
    updateGroupUrls();
}

function updateUserUrls()
{
    printfnq("Updating user URLs...\n");

    // XXX: only update user URLs where out-of-date

    $user = new User();
    if ($user->find()) {
        while ($user->fetch()) {
            printfv("Updating user {$user->nickname}...");
            try {
                $profile = $user->getProfile();

                updateProfileUrl($profile);
            } catch (Exception $e) {
                echo "Error updating URLs: " . $e->getMessage();
            }
            printfv("DONE.");
        }
    }
}

function updateProfileUrl($profile)
{
    $orig = clone($profile);
    $profile->profileurl = common_profile_url($profile->nickname);
    $profile->update($orig);
}

function updateGroupUrls()
{
    printfnq("Updating group URLs...\n");

    $group = new User_group();

    if ($group->find()) {
        while ($group->fetch()) {
            try {
                printfv("Updating group {$group->nickname}...");
                $orig = User_group::getKV('id', $group->id);
                if (!empty($group->original_logo)) {
                    $group->original_logo = Avatar::url(basename($group->original_logo));
                    $group->homepage_logo = Avatar::url(basename($group->homepage_logo));
                    $group->stream_logo = Avatar::url(basename($group->stream_logo));
                    $group->mini_logo = Avatar::url(basename($group->mini_logo));
                }
                // XXX: this is a hack to see if a group is local or not
                $localUri = common_local_url('groupbyid',
                                             array('id' => $group->id));
                if ($group->getUri() != $localUri) {
                    $group->mainpage = common_local_url('showgroup',
                                                        array('nickname' => $group->nickname));
                }
                $group->update($orig);
                printfv("DONE.");
            } catch (Exception $e) {
                echo "Can't update avatars for group " . $group->nickname . ": ". $e->getMessage();
            }
        }
    }
}

main();


code:
#!/usr/bin/env php
<?php
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2008-2011 StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));

$shortoptions = 'dfx::';
$longoptions = array('debug', 'files', 'extensions=');

$helptext = <<<END_OF_UPGRADE_HELP
php upgrade.php [options]
Upgrade database schema and data to latest software

END_OF_UPGRADE_HELP;

require_once INSTALLDIR.'/scripts/commandline.inc';

if (!defined('DEBUG')) {
    define('DEBUG', (bool)have_option('d', 'debug'));
}

function main()
{
    // "files" option enables possibly disk/resource intensive operations
    // that aren't really _required_ for the upgrade
    $iterate_files = (bool)have_option('f', 'files');

    if (Event::handle('StartUpgrade')) {
        fixupConversationURIs();

        updateSchemaCore();
        updateSchemaPlugins();

        // These replace old "fixup_*" scripts

        fixupNoticeConversation();
        initConversation();
        fixupGroupURI();
        if ($iterate_files) {
            printfnq("Running file iterations:\n");
            printfnq("* "); fixupFileGeometry();
            printfnq("* "); deleteLocalFileThumbnailsWithoutFilename();
            printfnq("* "); deleteMissingLocalFileThumbnails();
            printfnq("* "); fixupFileThumbnailUrlhash();
            printfnq("* "); setFilehashOnLocalFiles();
            printfnq("DONE.\n");
        } else {
            printfnq("Skipping intensive/long-running file iteration functions (enable with -f, should be done at least once!)\n");
        }

        initGroupProfileId();
        initLocalGroup();
        initNoticeReshare();

        initSubscriptionURI();
        initGroupMemberURI();

        initProfileLists();

        migrateProfilePrefs();

        Event::handle('EndUpgrade');
    }
}

function tableDefs()
{
	$schema = array();
	require INSTALLDIR.'/db/core.php';
	return $schema;
}

function updateSchemaCore()
{
    printfnq("Upgrading core schema...");

    $schema = Schema::get();
    $schemaUpdater = new SchemaUpdater($schema);
    foreach (tableDefs() as $table => $def) {
        $schemaUpdater->register($table, $def);
    }
    $schemaUpdater->checkSchema();

    printfnq("DONE.\n");
}

function updateSchemaPlugins()
{
    printfnq("Upgrading plugin schema...");

    Event::handle('BeforePluginCheckSchema');
    Event::handle('CheckSchema');

    printfnq("DONE.\n");
}

function fixupNoticeConversation()
{
    printfnq("Ensuring all notices have a conversation ID...");

    $notice = new Notice();
    $notice->whereAdd('conversation is null');
    $notice->whereAdd('conversation = 0', 'OR');
    $notice->orderBy('id'); // try to get originals before replies
    $notice->find();

    while ($notice->fetch()) {
        try {
            $cid = null;

            $orig = clone($notice);

            if (!empty($notice->reply_to)) {
                $reply = Notice::getKV('id', $notice->reply_to);

                if ($reply instanceof Notice && !empty($reply->conversation)) {
                    $notice->conversation = $reply->conversation;
                }
                unset($reply);
            }

            // if still empty
            if (empty($notice->conversation)) {
                $child = new Notice();
                $child->reply_to = $notice->getID();
                $child->limit(1);
                if ($child->find(true) && !empty($child->conversation)) {
                    $notice->conversation = $child->conversation;
                }
                unset($child);
            }

            // if _still_ empty we just create our own conversation
            if (empty($notice->conversation)) {
                $notice->conversation = $notice->getID();
            }

            $result = $notice->update($orig);

            unset($orig);
        } catch (Exception $e) {
            print("Error setting conversation: " . $e->getMessage());
        }
    }

    printfnq("DONE.\n");
}

function fixupGroupURI()
{
    printfnq("Ensuring all groups have an URI...");

    $group = new User_group();
    $group->whereAdd('uri IS NULL');

    if ($group->find()) {
        while ($group->fetch()) {
            $orig = User_group::getKV('id', $group->id);
            $group->uri = $group->getUri();
            $group->update($orig);
        }
    }

    printfnq("DONE.\n");
}

function initConversation()
{
    if (common_config('fix', 'upgrade_initConversation') <= 1) {
        printfnq(sprintf("Skipping %s, fixed by previous upgrade.\n", __METHOD__));
        return;
    }

    printfnq("Ensuring all conversations have a row in conversation table...");

    $notice = new Notice();
    $notice->selectAdd();
    $notice->selectAdd('DISTINCT conversation');
    $notice->joinAdd(['conversation', 'conversation:id'], 'LEFT');  // LEFT to get the null values for conversation.id
    $notice->whereAdd('conversation.id IS NULL');

    if ($notice->find()) {
        printfnq(" fixing {$notice->N} missing conversation entries...");
    }

    while ($notice->fetch()) {

        $id = $notice->conversation;

        $uri = common_local_url('conversation', array('id' => $id));

        // @fixme db_dataobject won't save our value for an autoincrement
        // so we're bypassing the insert wrappers
        $conv = new Conversation();
        $sql = "insert into conversation (id,uri,created) values(%d,'%s','%s')";
        $sql = sprintf($sql,
                       $id,
                       $conv->escape($uri),
                       $conv->escape(common_sql_now()));
        $conv->query($sql);
    }

    // This is something we should only have to do once unless introducing new, bad code.
    if (DEBUG) printfnq(sprintf('Storing in config that we have done %s', __METHOD__));
    common_config_set('fix', 'upgrade_initConversation', 1);

    printfnq("DONE.\n");
}

function fixupConversationURIs()
{
    printfnq("Ensuring all conversations have a URI...");

    $conv = new Conversation();
    $conv->whereAdd('uri IS NULL');

    if ($conv->find()) {
        $rounds = 0;
        while ($conv->fetch()) {
            $uri = common_local_url('conversation', array('id' => $conv->id));
            $sql = sprintf('UPDATE conversation SET uri="%1$s" WHERE id="%2$d";',
                            $conv->escape($uri), $conv->id);
            $conv->query($sql);
            if (($conv->N-++$rounds) % 500 == 0) {
                printfnq(sprintf(' %d items left...', $conv->N-$rounds));
            }
        }
    }

    printfnq("DONE.\n");
}

function initGroupProfileId()
{
    printfnq("Ensuring all User_group entries have a Profile and profile_id...");

    $group = new User_group();
    $group->whereAdd('NOT EXISTS (SELECT id FROM profile WHERE id = user_group.profile_id)');
    $group->find();

    while ($group->fetch()) {
        try {
            // We must create a new, incrementally assigned profile_id
            $profile = new Profile();
            $profile->nickname   = $group->nickname;
            $profile->fullname   = $group->fullname;
            $profile->profileurl = $group->mainpage;
            $profile->homepage   = $group->homepage;
            $profile->bio        = $group->description;
            $profile->location   = $group->location;
            $profile->created    = $group->created;
            $profile->modified   = $group->modified;

            $profile->query('BEGIN');
            $id = $profile->insert();
            if (empty($id)) {
                $profile->query('ROLLBACK');
                throw new Exception('Profile insertion failed, profileurl: '.$profile->profileurl);
            }
            $group->query("UPDATE user_group SET profile_id={$id} WHERE id={$group->id}");
            $profile->query('COMMIT');

            $profile->free();
        } catch (Exception $e) {
            printfv("Error initializing Profile for group {$group->nickname}:" . $e->getMessage());
        }
    }

    printfnq("DONE.\n");
}

function initLocalGroup()
{
    printfnq("Ensuring all local user groups have a local_group...");

    $group = new User_group();
    $group->whereAdd('NOT EXISTS (select group_id from local_group where group_id = user_group.id)');
    $group->find();

    while ($group->fetch()) {
        try {
            // Hack to check for local groups
            if ($group->getUri() == common_local_url('groupbyid', array('id' => $group->id))) {
                $lg = new Local_group();

                $lg->group_id = $group->id;
                $lg->nickname = $group->nickname;
                $lg->created  = $group->created; // XXX: common_sql_now() ?
                $lg->modified = $group->modified;

                $lg->insert();
            }
        } catch (Exception $e) {
            printfv("Error initializing local group for {$group->nickname}:" . $e->getMessage());
        }
    }

    printfnq("DONE.\n");
}

function initNoticeReshare()
{
    if (common_config('fix', 'upgrade_initNoticeReshare') <= 1) {
        printfnq(sprintf("Skipping %s, fixed by previous upgrade.\n", __METHOD__));
        return;
    }

    printfnq("Ensuring all reshares have the correct verb and object-type...");

    $notice = new Notice();
    $notice->whereAdd('repeat_of is not null');
    $notice->whereAdd('(verb != "'.ActivityVerb::SHARE.'" OR object_type != "'.ActivityObject::ACTIVITY.'")');

    if ($notice->find()) {
        while ($notice->fetch()) {
            try {
                $orig = Notice::getKV('id', $notice->id);
                $notice->verb = ActivityVerb::SHARE;
                $notice->object_type = ActivityObject::ACTIVITY;
                $notice->update($orig);
            } catch (Exception $e) {
                printfv("Error updating verb and object_type for {$notice->id}:" . $e->getMessage());
            }
        }
    }

    // This is something we should only have to do once unless introducing new, bad code.
    if (DEBUG) printfnq(sprintf('Storing in config that we have done %s', __METHOD__));
    common_config_set('fix', 'upgrade_initNoticeReshare', 1);

    printfnq("DONE.\n");
}

function initSubscriptionURI()
{
    printfnq("Ensuring all subscriptions have a URI...");

    $sub = new Subscription();
    $sub->whereAdd('uri IS NULL');

    if ($sub->find()) {
        while ($sub->fetch()) {
            try {
                $sub->decache();
                $sub->query(sprintf('update subscription '.
                                    'set uri = "%s" '.
                                    'where subscriber = %d '.
                                    'and subscribed = %d',
                                    $sub->escape(Subscription::newUri($sub->getSubscriber(), $sub->getSubscribed(), $sub->created)),
                                    $sub->subscriber,
                                    $sub->subscribed));
            } catch (Exception $e) {
                common_log(LOG_ERR, "Error updated subscription URI: " . $e->getMessage());
            }
        }
    }

    printfnq("DONE.\n");
}

function initGroupMemberURI()
{
    printfnq("Ensuring all group memberships have a URI...");

    $mem = new Group_member();
    $mem->whereAdd('uri IS NULL');

    if ($mem->find()) {
        while ($mem->fetch()) {
            try {
                $mem->decache();
                $mem->query(sprintf('update group_member set uri = "%s" '.
                                    'where profile_id = %d ' .
                                    'and group_id = %d ',
                                    Group_member::newUri(Profile::getByID($mem->profile_id), User_group::getByID($mem->group_id), $mem->created),
                                    $mem->profile_id,
                                    $mem->group_id));
            } catch (Exception $e) {
                common_log(LOG_ERR, "Error updated membership URI: " . $e->getMessage());
          }
        }
    }

    printfnq("DONE.\n");
}

function initProfileLists()
{
    printfnq("Ensuring all profile tags have a corresponding list...");

    $ptag = new Profile_tag();
    $ptag->selectAdd();
    $ptag->selectAdd('tagger, tag, count(*) as tagged_count');
    $ptag->whereAdd('NOT EXISTS (SELECT tagger, tagged from profile_list '.
                    'where profile_tag.tagger = profile_list.tagger '.
                    'and profile_tag.tag = profile_list.tag)');
    $ptag->groupBy('tagger, tag');
    $ptag->orderBy('tagger, tag');

    if ($ptag->find()) {
        while ($ptag->fetch()) {
            $plist = new Profile_list();

            $plist->tagger   = $ptag->tagger;
            $plist->tag      = $ptag->tag;
            $plist->private  = 0;
            $plist->created  = common_sql_now();
            $plist->modified = $plist->created;
            $plist->mainpage = common_local_url('showprofiletag',
                                                array('tagger' => $plist->getTagger()->nickname,
                                                      'tag'    => $plist->tag));;

            $plist->tagged_count     = $ptag->tagged_count;
            $plist->subscriber_count = 0;

            $plist->insert();

            $orig = clone($plist);
            // After insert since it uses auto-generated ID
            $plist->uri      = common_local_url('profiletagbyid',
                                        array('id' => $plist->id, 'tagger_id' => $plist->tagger));

            $plist->update($orig);
        }
    }

    printfnq("DONE.\n");
}

/*
 * Added as we now store interpretd width and height in File table.
 */
function fixupFileGeometry()
{
    printfnq("Ensuring width and height is set for supported local File objects...");

    $file = new File();
    $file->whereAdd('filename IS NOT NULL');    // local files
    $file->whereAdd('width IS NULL OR width = 0');

    if ($file->find()) {
        while ($file->fetch()) {
            if (DEBUG) printfnq(sprintf('Found file without width: %s\n', _ve($file->getFilename())));

            // Set file geometrical properties if available
            try {
                $image = ImageFile::fromFileObject($file);
            } catch (ServerException $e) {
                // We couldn't make out an image from the file.
                if (DEBUG) printfnq(sprintf('Could not make an image out of the file.\n'));
                continue;
            }
            $orig = clone($file);
            $file->width = $image->width;
            $file->height = $image->height;
            if (DEBUG) printfnq(sprintf('Setting image file and with to %sx%s.\n', $file->width, $file->height));
            $file->update($orig);

            // FIXME: Do this more automagically inside ImageFile or so.
            if ($image->getPath() != $file->getPath()) {
                if (DEBUG) printfnq(sprintf('Deleting the temporarily stored ImageFile.\n'));
                $image->unlink();
            }
            unset($image);
        }
    }

    printfnq("DONE.\n");
}

/*
 * File_thumbnail objects for local Files store their own filenames in the database.
 */
function deleteLocalFileThumbnailsWithoutFilename()
{
    printfnq("Removing all local File_thumbnail entries without filename property...");

    $file = new File();
    $file->whereAdd('filename IS NOT NULL');    // local files

    if ($file->find()) {
        // Looping through local File entries
        while ($file->fetch()) {
            $thumbs = new File_thumbnail();
            $thumbs->file_id = $file->id;
            $thumbs->whereAdd('filename IS NULL OR filename = ""');
            // Checking if there were any File_thumbnail entries without filename
            if (!$thumbs->find()) {
                continue;
            }
            // deleting incomplete entry to allow regeneration
            while ($thumbs->fetch()) {
                $thumbs->delete();
            }
        }
    }

    printfnq("DONE.\n");
}

/*
 * Delete File_thumbnail entries where the referenced file does not exist.
 */
function deleteMissingLocalFileThumbnails()
{
    printfnq("Removing all local File_thumbnail entries without existing files...");

    $thumbs = new File_thumbnail();
    $thumbs->whereAdd('filename IS NOT NULL AND filename != ""');
    // Checking if there were any File_thumbnail entries without filename
    if ($thumbs->find()) {
        while ($thumbs->fetch()) {
            try {
                $thumbs->getPath();
            } catch (FileNotFoundException $e) {
                $thumbs->delete();
            }
        }
    }

    printfnq("DONE.\n");
}

/*
 * Files are now stored with their hash, so let's generate for previously uploaded files.
 */
function setFilehashOnLocalFiles()
{
    printfnq('Ensuring all local files have the filehash field set...');

    $file = new File();
    $file->whereAdd('filename IS NOT NULL AND filename != ""');        // local files
    $file->whereAdd('filehash IS NULL', 'AND');     // without filehash value

    if ($file->find()) {
        while ($file->fetch()) {
            try {
                $orig = clone($file);
                $file->filehash = hash_file(File::FILEHASH_ALG, $file->getPath());
                $file->update($orig);
            } catch (FileNotFoundException $e) {
                echo "\n    WARNING: file ID {$file->id} does not exist on path '{$e->path}'. If there is no file system error, run: php scripts/clean_file_table.php";
            }
        }
    }

    printfnq("DONE.\n");
}

function fixupFileThumbnailUrlhash()
{
    printfnq("Setting urlhash for File_thumbnail entries: ");

    $thumb = new File_thumbnail();
    $thumb->query('UPDATE '.$thumb->escapedTableName().' SET urlhash=SHA2(url, 256) WHERE'.
                    ' url IS NOT NULL AND'. // find all entries with a url value
                    ' url != "" AND'.       // precaution against non-null empty strings
                    ' urlhash IS NULL');    // but don't touch those we've already calculated

    printfnq("DONE.\n");
}

function migrateProfilePrefs()
{
    printfnq("Finding and possibly migrating Profile_prefs entries: ");

    $prefs = array();   // ['qvitter' => ['cover_photo'=>'profile_banner_url', ...], ...]
    Event::handle('GetProfilePrefsMigrations', array(&$prefs));

    foreach($prefs as $namespace=>$mods) {
        echo "$namespace... ";
        assert(is_array($mods));
        $p = new Profile_prefs();
        $p->namespace = $namespace;
        // find all entries in all modified topics given in this namespace
        $p->whereAddIn('topic', array_keys($mods), $p->columnType('topic'));
        $p->find();
        while ($p->fetch()) {
            // for each entry, update 'topic' to the new key value
            $orig = clone($p);
            $p->topic = $mods[$p->topic];
            $p->updateWithKeys($orig);
        }
    }

    printfnq("DONE.\n");
}

main();