code:
Configuration options
================================================================================

The main configuration file for GNU social (excepting configurations for
dependency software) is config.php in your GNU social directory. If you edit any
other file in the directory, like `lib/default.php` (where most of the defaults
are defined), you will lose your configuration options in any upgrade, and you
will wish that you had been more careful.

Starting with version 0.9.0, a Web based configuration panel has been added to
GNU social. The preferred method for changing config options is to use this
panel.

A command-line script, setconfig.php, can be used to set individual
configuration options. It's in the scripts/ directory.

Starting with version 0.7.1, you can put config files in the /etc/GNU social/
directory on your server, if it exists. Config files will be included in this
order:

* `/etc/GNU social/statusnet.php` - server-wide config

* `/etc/GNU social/<servername>.php` - for a virtual host

* `/etc/GNU social/<servername>_<pathname>.php` - for a path

* `INSTALLDIR/config.php` - for a particular implementation

Almost all configuration options are made through a two-dimensional
associative array, cleverly named $config. A typical configuration
line will be:

    $config['section']['option'] = value;

For brevity, the following documentation describes each section and
option.

site
-------------------------------------------------------------------------------

This section is a catch-all for site-wide variables.

* `name` (string, required, default "Another GNU social Instance"): the name of
    your site, like 'YourCompany Microblog'.

* `server` (string, required, default null): the server part of your site's URLs,
    like 'example.net'.

* `path` (string, required, default ''): The path part of your site's URLs, like
    'statusnet' or '' (installed in root).

* `fancy` (string, default false): whether or not your site uses fancy URLs (see Fancy URLs
    section above).

* `logfile` (string, default './'): full path to a file for GNU social to save
    logging information to. You may want to use this if you don't have access
    to syslog.

* `logdebug` (boolean, default false): whether to log additional debug info like
    backtraces on hard errors.

* `locale_path` (string, default null): full path to the directory for locale
    data. Unless you store all your locale data in one place, you probably
    don't need to use this.

* `language` (string, default "en_us"): default language for your site. Defaults
    to US English. Note that this is overridden if a user is logged in and has
    selected a different language. It is also overridden if the user is NOT
    logged in, but their browser requests a different langauge. Since pretty
    much everybody's browser requests a language, that means that changing
    this setting has little or no effect in practice.

* `languages` (array, default null): A list of languages supported on your site.
    Typically you'd only change this if you wanted to disable support for one or
    another language:

    "unset($config['site']['languages']['de'])" will disable
    support for German.

* `theme` (string, default 'default'): Theme for your site (see Theme section).
    Two themes are provided by default: 'default' and 'stoica' (the one used by
    Identi.ca). It's appreciated if you don't use the 'stoica' theme except as
    the basis for your own.

* `email` (string, required): contact email address for your site. By default,
    it's extracted from your Web server environment; you may want to customize it.

* `broughtbyurl` (string, default null): name of an organization or individual
    who provides the service. Each page will include a link to this name in the
    footer. A good way to link to the blog, forum, wiki, corporate portal, or
    whoever is making the service available.

* `broughtby` (string, default null): text used for the "brought by" link.

* `timezone` (string, default 'UTC'): default timezone for message display. Users
    can set their own time zone. Defaults to 'UTC', which is a pretty good
    default.

* `closed` (boolean, default false): If set to 'true', will disallow registration
    on your site.  This is a cheap way to restrict accounts to only one
    individual or group; just register the accounts you want on the service,
    *then* set this variable to 'true'.

* `inviteonly` (boolean, default false): If set to 'true', will only allow
    registration if the user was invited by an existing user.

* `private` (boolean, default false): If set to 'true', anonymous users will be
    redirected to the 'login' page. Also, API methods that normally require no
    authentication will require it. Note that this does not turn off
    registration; use 'closed' or 'inviteonly' for the behaviour you want.

* `notice` (string, default null): A plain string that will appear on every
    page. A good place to put introductory information about your service, or
    info about upgrades and outages, or other community info. Any HTML will be
    escaped.

* `logo` (string, default null): URL of an image file to use as the logo for the
    site. Overrides the logo in the theme, if any.

* `ssllogo` (string, default null): URL of an image file to use as the logo on
    SSL pages. If unset, theme logo is used instead.

* `ssl` (enum['always','sometimes','never'], default 'never'): Whether to use SSL
    and https:// URLs for some or all pages.

    Possible values are 'always' (use it for all pages), 'never' (don't use it
    for any pages), or 'sometimes' (use it for sensitive pages that include
    passwords like login and registration, but not for regular pages).

* `sslproxy` (boolean, default false): Whether to force GNUsocial to think it
    is HTTPS when the server gives no such information. I.e. when you're using
    a reverse proxy that adds the encryption layer but the webserver that runs
    PHP isn't configured with a key and certificate.

* `sslserver` (string, default null): use an alternate server name for SSL URLs,
    like 'secure.example.org'. You should be careful to set cookie parameters
    correctly so that both the SSL server and the "normal" server can access
    the session cookie and preferably other cookies as well.

* `dupelimit` (integer, default 60): minimum time allowed for one person to say
    the same thing twice. Default 60s. Anything lower is considered a user or
    UI error.

* `textlimit` (integer, default 0): default max size for texts in the site. Can
    be fine-tuned for notices, messages, profile bios and group descriptions.
    Zero indicates no limit.

* favicon: the path to a custom favicon, eg: favicon.png

* `x-static-delivery` (string, default null): when a string, use this
    as the header with wich to serve static files. Possible values are
    'X-Sendfile' (for Apache and others) and 'X-Accel-Redirect' (for
    nginx).

db
-------------------------------------------------------------------------------

This section is a reference to the configuration options for
`DB_DataObject` (see
<http://pear.php.net/manual/en/package.database.db-dataobject.intro-configuration.php>).
The ones that you may want to set are listed below for clarity.

* `database` (string, required, default null): a DSN (Data Source Name) for your
    GNU social database. This is in the format
    'protocol://username:password@hostname/databasename', where 'protocol' is '
    mysql' or 'mysqli' (or possibly 'postgresql', if you really know what
    you're doing), 'username' is the username, 'password' is the password,
    and etc.

* `ini_yourdbname` (string, default null): if your database is not named 'statusnet',
    you'll need to set this to point to the location of the statusnet.ini file.
    Note that the real name of your database should go in there, not literally
    'yourdbname'.

* `db_driver`(enum['DB','MDB2'], default null): You can try changing this to
    'MDB2' to use the other driver type for DB_DataObject, but note that it
    breaks the OpenID libraries, which only support PEAR::DB.

* `quote_identifiers`(boolean, default false): Set this to true if you're using
    postgresql.

* `type` (enum["mysql", "postgresql"], default 'mysql'): Used for certain
    database-specific optimization code.  Assumes mysql if not set.  MySQL also
    covers MySQLi and MariaDB.

* `mirror` (array, default null): you can set this to an array of DSNs, in the
    format of the above 'database' value. If it's set, certain read-only
    actions will use a random value out of this array for the database, rather
    than the one in 'database' (actually, 'database' is overwritten). You can
    offload a busy DB server by setting up MySQL replication and adding the
    slaves to this array. Note that if you want some requests to go to the
    'database' (master) server, you'll need to include it in this array, too.

* `utf8` (boolean, true): whether to talk to the database in UTF-8 mode. This is
    the default with new installations, but older sites may want to turn it off
    until they get their databases fixed up. See "UTF-8 database" above for
    details.

* `schemacheck` (enum["runtime", "script"], default "runtime"): when
    to let plugins check the database schema to add tables or update
    them. 'runtime' can be costly (plugins check the schema on every
    hit, adding potentially several db queries, some quite long), but
    not everyone knows how to run a script or has the access in their
    hosting environment to do so. If you can, set this to 'script' and
    run scripts/checkschema.php whenever you install or upgrade a
    plugin.

syslog
-------------------------------------------------------------------------------

By default, GNU social sites log error messages to the syslog facility.
(You can override this using the 'logfile' parameter described above).

* `appname` (string, default `'GNU social'`): The name that GNU social uses to log
    messages. By default it's "GNU social", but if you have more than one
    installation on the server, you may want to change the name for each
    instance so you can track log messages more easily.

* `facility` (string, default `'LOG_USER'`): what syslog facility to use. Only set
    this if you know what syslog is and have a good reason to change it.

queue
-------------------------------------------------------------------------------

You can configure the software to queue time-consuming tasks, like
sending out SMS email or XMPP messages, for off-line processing. See
'Queues and daemons' above for how to set this up.

* `enabled` (boolean, default false): Whether to uses queues.

* `daemon` (boolean, default false): Wather to use queuedaemon. False means
    you'll use OpportunisticQM plugin.

* `subsystem` (enum["db", "stomp"], default 'db'): Which kind of queueserver to
    use. Values include "db" for our hacked-together database queuing (no
    other server required), "stomp" for a stomp server, and "redis" for a Redis
	server.

* `threads` (int): How many queue "threads" (actually processes) to run. Defaults to
    number of cpu cores in unix-like systems or 1 on other OSes.

* `items_to_handle` (int): How many items to handle before a daemon process exits.
    Default to unlimited.

* `stomp_server` (string, default null): "broker URI" for stomp server.
    Something like "tcp://hostname:61613". More complicated ones are possible;
    see your stomp server's documentation for details.

* `queue_basename` (string, default null): a root name to use for queues (stomp
    only). Typically something like '/queue/sitename/' makes sense. If running
    multiple instances on the same server, make sure that either this setting
    or $config['site']['nickname'] are unique for each site to keep them
    separate.

* `stomp_username` (string, default null): username for connecting to the stomp
    server.

* `stomp_password` (string, default null): password for connecting to the stomp
    server.

* `stomp_persistent` (boolean, default true): Keep items across queue server
    restart, if enabled.  Note: Under ActiveMQ, the server configuration
    determines if and how persistent storage is actually saved.

    If using a message queue server other than ActiveMQ, you may
    need to disable this if it does not support persistence.

* `stomp_transactions` (boolean, default true): use transactions to aid in error
    detection. A broken transaction will be seen quickly, allowing a message to
    be redelivered immediately if a daemon crashes.

    If using a message queue server other than ActiveMQ, you may need to
    disable this if it does not support transactions.

* `stomp_acks` (boolean, default true): send acknowledgements to aid in flow
    control. An acknowledgement of successful processing tells the server we're
    ready for more and can help keep things moving smoothly.

    This should *not* be turned off when running with ActiveMQ, (it breaks if
    you do), but if using another message queue server that does not support
    acknowledgements you might need to disable this.

* `softlimit` (integer): an absolute or relative "soft memory limit"; daemons
    will restart themselves gracefully when they find they've hit this amount
    of memory usage. Defaults to 90% of PHP's global memory_limit setting.

* `inboxes` (boolean, default true): delivery of messages to receiver's inboxes
    can be delayed to queue time for best interactive performance on the
    sender. This may however be annoyingly slow when using the DB queues, so
    you can set this to false if it's causing trouble.

* `breakout` (array, default null): for stomp, individual queues are by default
    grouped up for best scalability. If some need to be run by separate daemons,
    etc they can be manually adjusted here.

        Default will share all queues for all sites within each group.
        Specify as <group>/<queue> or <group>/<queue>/<site>,
        using nickname identifier as site.

        'main/distrib' separate "distrib" queue covering all sites
        'xmpp/xmppout/mysite' separate "xmppout" queue covering just 'mysite'

* `max_retries` (integer, default 10): for stomp, drop messages after N failed
    attempts to process.

* `dead_letter_dir` (string, default null): for stomp, optional directory to dump
    data on failed queue processing events after discarding them.

* `stomp_no_transactions` (boolean, default false): for stomp, the server does
    not support transactions, so do not try to user them. This is needed for
    http://www.morbidq.com/

* `stomp_no_acks` (boolean, default false): for stomp, the server does not
    support acknowledgements so do not try to user them. This is needed for
    http://www.morbidq.com/.

license
-------------------------------------------------------------------------------

The default license to use for your users notices. The default is the
Creative Commons Attribution 3.0 license, which is probably the right
choice for any public site. Note that some other servers will not
accept notices if you apply a stricter license than this.

As of 2016, this is largely disregarded in the Fediverse -mb

* `type` (enum["cc", "allrightsreserved", "private"], default 'cc'): one of
    'cc' (for Creative Commons licenses), 'allrightsreserved' (default
    copyright), or 'private' (for private and confidential information).

* `owner` (string, default 'contributors'): for 'allrightsreserved' or
    'private', an assigned copyright holder (for example, an employer for a
    private site).

* `url` (string, default null): URL of the license, used for links.

* `title` (string, default null): Title for the license, like 'Creative Commons
    Attribution 3.0'.

* `image` (string, default null): URL of a button shown on each page for the
    license.

mail
-------------------------------------------------------------------------------

This is for configuring out-going email. We use PEAR's Mail module,
see: http://pear.php.net/manual/en/package.mail.mail.factory.php

* `backend` (enum["mail", "sendmail", "smtp"], default 'mail'): The backend to
   use for mail.  While this defaults to PEAR mail, we recommend SMTP where your
   setup supports it as it is of the three the more difficult one for script
   exploits to abuse (relatively speaking - they all have potential problems.)

* `params` (array, default null): if the mail backend requires any parameters,
    you can provide them in an associative array.

* `templates_path` (string, default null): alias for `site->mail_path`

nickname
-------------------------------------------------------------------------------

This is for configuring nicknames in the service.

* `blacklist` (array, default null): an array of strings for usernames that
    may not be registered. A hard-coded default array exists for strings that
    are used by GNU social (e.g. 'doc', 'main', 'avatar', 'theme') but you may
    want to add others if you have other software installed in a subdirectory
    of GNU social or if you just don't want certain words used as usernames.

* `featured` (array, default null): an array of nicknames of 'featured' users of
    the site. Can be useful to draw attention to well-known users, or
    interesting people, or whatever.

avatar
-------------------------------------------------------------------------------

For configuring avatar access.

* `dir` (string, default './avatar'): Directory to look for avatar files and to
    put them into. Defaults to avatar subdirectory of install directory; if
    you change it, make sure to change path, too.

* `path` (string, 'default './avatar'): Path to avatars. Defaults to path for
    avatar subdirectory, but you can change it if you wish. Note that this will
    be included with the avatar server, too.

* `server` (string, default null): If set, defines another server where avatars
    are stored in the root directory. Note that the 'avatar' subdir still has
    to be writeable. You'd typically use this to split HTTP requests on the
    client to speed up page loading, either with another virtual server or
    with an NFS or SAMBA share. Clients typically only make 2 connections to a
    single server at a time
    <https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.1.4>,
    so this can parallelize the job.

* `ssl` (boolean, default null): Whether to access avatars using HTTPS. Defaults
    to null, meaning to guess based on site-wide SSL settings.

public
-------------------------------------------------------------------------------

For configuring the public stream.

* `localonly` (boolean, default true): If set to true, only messages posted by
    users of this service (rather than other services, filtered through
    OStatus) are shown in the public stream. Default true.

* `blacklist` (array, default null): An array of IDs of users to hide from the
    public stream. Useful if you have someone making excessive Twitterfeed
    posts to the site, other kinds of automated posts, testing bots, etc.

* `autosource` (array, default null): Sources of notices that are from automatic
    posters, and thus should be kept off the public timeline.

theme
-------------------------------------------------------------------------------

* `server` (string, default null): Like avatars, you can speed up page loading
    by pointing the theme file lookup to another server (virtual or real).
    The default of null will use the same server as PA.

* `dir` (string, default "./themes"): Directory where theme files are stored.
    Used to determine whether to show parts of a theme file. Defaults to the
    theme subdirectory of the install directory.

* `path` (string, default null): Path part of theme URLs, before the theme name. Relative to the
    theme server. It may make sense to change this path when upgrading,
    (using version numbers as the path) to make sure that all files are
    reloaded by caching clients or proxies. Defaults to null,
    which means to use the site path + '/theme'.

* `ssl` (boolean, default null): Whether to use SSL for theme elements. Default
    is null, which means guess based on site SSL settings.

* `sslserver` (string, default null): SSL server to use when page is
    HTTPS-encrypted. If unspecified, site ssl server and so on will be used.

* `sslpath` (string, default null): If sslserver if defined, path to use when
    page is HTTPS-encrypted.

javascript
-------------------------------------------------------------------------------

* `server` (string, default null): You can speed up page loading by pointing the
    theme file lookup to another server (virtual or real). Defaults to NULL,
    meaning to use the site server.

* `path` (string default null): Path part of Javascript URLs. Defaults to null,
    which means to use the site path + '/js/'.

* `ssl` (boolean, default null): Whether to use SSL for JavaScript files.
    Default is null, which means guess based on site SSL settings.

* `sslserver` (string, default null): SSL server to use when page is HTTPS-
    encrypted. If unspecified, site ssl server and so on will be used.

* `sslpath` (string, default null): If sslserver if defined, path to use when
    page is HTTPS-encrypted.

* `bustframes` (boolean, default true): If true, all web pages will break out of
    framesets. If false, can comfortably live in a frame or iframe... probably.

xmpp
-------------------------------------------------------------------------------

For configuring the XMPP sub-system.

* `enabled` (boolean, default false): Whether to accept and send messages by
    XMPP. Default false.

* `server` (string, default null): Server part of XMPP ID for update user.

* `port` (integer, default 5222): Connection port for clients.

* `user` (string, default null): Username for the client connection. Users will
    receive messages from 'user'@'server'.

* `resource`: a unique identifier for the connection to the server. This
    is actually used as a prefix for each XMPP component in the system.

* `password`: password for the user account.

* `host`: some XMPP domains are served by machines with a different
    hostname. Set this to the correct hostname if that's the
    case with your server.

* `encryption`: Whether to encrypt the connection between GNU social and the
    XMPP server. Defaults to true, but you can get
    considerably better performance turning it off if you're
    connecting to a server on the same machine or on a
    protected network.

* `debug`: if turned on, this will make the XMPP library blurt out all of
    the incoming and outgoing messages as XML stanzas. Use as a
    last resort, and never turn it on if you don't have queues
    enabled, since it will spit out sensitive data to the browser.

* `public`: an array of JIDs to send _all_ notices to. This is useful for
    participating in third-party search and archiving services.

invite
-------------------------------------------------------------------------------

For configuring invites.

* `enabled`: Whether to allow users to send invites. Default true.

tag
-------------------------------------------------------------------------------

Miscellaneous tagging stuff.

* `dropoff`: Decay factor for tag listing, in seconds.
    Defaults to exponential decay over ten days; you can twiddle
    with it to try and get better results for your site.

popular
-------------------------------------------------------------------------------

Settings for the "popular" section of the site.

* `dropoff`: Decay factor for popularity listing, in seconds.
    Defaults to exponential decay over ten days; you can twiddle
    with it to try and get better results for your site.

daemon
-------------------------------------------------------------------------------

For daemon processes.

* `piddir`: directory that daemon processes should write their PID file
    (process ID) to. Defaults to /var/run/, which is where this
    stuff should usually go on Unix-ish systems.

* `user`: If set, the daemons will try to change their effective user ID
    to this user before running. Probably a good idea, especially if
    you start the daemons as root. Note: user name, like 'daemon',
    not 1001.

* `group`: If set, the daemons will try to change their effective group ID
    to this named group. Again, a name, not a numerical ID.

emailpost
-------------------------------------------------------------------------------

For post-by-email.

* `enabled`: Whether to enable post-by-email. Defaults to true. You will
    also need to set up maildaemon.php.

sms
-------------------------------------------------------------------------------

For SMS integration.

* `enabled`: Whether to enable SMS integration. Defaults to true. Queues
    should also be enabled.

integration
-------------------------------------------------------------------------------

A catch-all for integration with other systems.

* `taguri`: base for tag:// URIs. Defaults to site-server + ',2009'.

inboxes
-------------------------------------------------------------------------------

For notice inboxes.

* `enabled`: No longer used. If you set this to something other than true,
    GNU social will no longer run.

throttle
-------------------------------------------------------------------------------

For notice-posting throttles.

* `enabled`: Whether to throttle posting. Defaults to false.

* `count`: Each user can make this many posts in 'timespan' seconds. So, if count
    is 100 and timespan is 3600, then there can be only 100 posts
    from a user every hour.

* `timespan`: see 'count'.

profile
-------------------------------------------------------------------------------

Profile management.

* `biolimit`: max character length of bio; 0 means no limit; null means to use
    the site text limit default.

* `backup`: whether users can backup their own profiles. Defaults to false.

* `restore`: whether users can restore their profiles from backup files. Defaults
	 to false.

* `delete`: whether users can delete their own accounts. Defaults to false.

* `move`: whether users can move their accounts to another server. Defaults
      to true.

newuser
-------------------------------------------------------------------------------

Options with new users.

* `default`: nickname of a user account to automatically subscribe new
    users to. Typically this would be system account for e.g.
    service updates or announcements. Users are able to unsub
    if they want. Default is null; no auto subscribe.

* `welcome`: nickname of a user account that sends welcome messages to new
    users. Can be the same as 'default' account, although on
    busy servers it may be a good idea to keep that one just for
    'urgent' messages. Default is null; no message.

If either of these special user accounts are specified, the users should
be created before the configuration is updated.

attachments
-------------------------------------------------------------------------------

The software lets users upload files with their notices. You can configure
the types of accepted files by mime types and a trio of quota options:
per file, per user (total), per user per month.

We suggest the use of the pecl file_info extension to handle mime type
detection.

* `supported`: an array of mime types you accept to store and distribute,
    like 'image/gif', 'video/mpeg', 'audio/mpeg', etc. Make sure you
    setup your server to properly recognize the types you want to
    support. It's important to use the result of calling `image_type_to_extension`
    for the appropriate image type, in the case of images. This is so all parts of
    the code see the same extension for each image type (jpg vs jpeg).
    For example, to enable BMP uploads, add this to the config.php file:
        $config['attachments']['supported'][image_type_to_mime_type(IMAGETYPE_GIF)]
        = image_type_to_extension(IMAGETYPE_GIF);
    See https://www.php.net/manual/en/function.image-type-to-mime-type.php for a
    list of such constants. If a filetype is not listed there, it's possible to add
    the mimetype and the extension by hand, but they need to match those returned by
    the file command.

* `uploads`: false to disable uploading files with notices (true by default).

For quotas, be sure you've set the upload_max_filesize and post_max_size
in php.ini to be large enough to handle your upload. In httpd.conf
(if you're using apache), check that the LimitRequestBody directive isn't
set too low (it's optional, so it may not be there at all).

* `extblacklist`: associative array to either deny certain extensions or
    change them to a different one. For example:

        $config['attachments']['extblacklist']['php'] = 'phps';  // this turns .php into .phps
        $config['attachments']['extblacklist']['exe'] = false;   // this would deny any uploads
                                                                 // of files with the "exe" extension

* `process_links`: follow redirects and save all available file information
    (mimetype, date, size, oembed, etc.). Defaults to true.

* `file_quota`: maximum size for a single file upload in bytes. A user can send
    any amount of notices with attachments as long as each attachment
    is smaller than file_quota.

* `user_quota`: total size in bytes a user can store on this server. Each user
    can store any number of files as long as their total size does
    not exceed the user_quota.

* `monthly_quota`: total size permitted in the current month. This is the total
    size in bytes that a user can upload each month.

* `dir`: directory accessible to the Web process where uploads should go.
    Defaults to the 'file' subdirectory of the install directory, which
    should be writeable by the Web user.

* `server`: server name to use when creating URLs for uploaded files.
    Defaults to null, meaning to use the default Web server. Using
    a virtual server here can speed up Web performance.

* `path`: URL path, relative to the server, to find files. Defaults to
    main path + '/file/'.

* `ssl`: whether to use HTTPS for file URLs. Defaults to null, meaning to
    guess based on other SSL settings.

* `sslserver`: if specified, this server will be used when creating HTTPS
    URLs. Otherwise, the site SSL server will be used, with /file/ path.

* `sslpath`: if this and the sslserver are specified, this path will be used
    when creating HTTPS URLs. Otherwise, the attachments|path value
    will be used.

* `show_thumbs`: show thumbnails in notice lists for uploaded images, and photos
    and videos linked remotely that provide oEmbed info. Defaults to true.

* `show_html`: show (filtered) text/html attachments (and oEmbed HTML etc.).
    Doesn't affect AJAX calls. Defaults to false.

* `filename_base`: for new files, choose one: 'upload', 'hash'. Defaults to hash.

group
-------------------------------------------------------------------------------

Options for group functionality.

* `maxaliases`: maximum number of aliases a group can have. Default 3. Set
    to 0 or less to prevent aliases in a group.

* `desclimit`: maximum number of characters to allow in group descriptions.
    null (default) means to use the site-wide text limits. 0
    means no limit.

* `addtag`: Whether to add a tag for the group nickname for every group post
	(pre-1.0.x behaviour). Defaults to false.

search
-------------------------------------------------------------------------------

Some stuff for search.

* `type`: type of search. Ignored if PostgreSQL or Sphinx are enabled. Can either
    be 'fulltext' or 'like' (default). The former is faster and more efficient
    but requires the lame old MyISAM engine for MySQL. The latter
    will work with InnoDB but could be miserably slow on large
    systems. We'll probably add another type sometime in the future,
    with our own indexing system (maybe like MediaWiki's).

sessions
-------------------------------------------------------------------------------

Session handling.

* `handle`: boolean. Whether we should register our own PHP session-handling
    code (using the database and cache layers if enabled). Defaults to false.
    Setting this to true makes some sense on large or multi-server
    sites, but it probably won't hurt for smaller ones, either.

* `debug`: whether to output debugging info for session storage. Can help
    with weird session bugs, sometimes. Default false.

ping
-------------------------------------------------------------------------------

Using the "XML-RPC Ping" method initiated by weblogs.com, the site can
notify third-party servers of updates.

* `notify`: an array of URLs for ping endpoints. Default is the empty
    array (no notification).

notice
-------------------------------------------------------------------------------

Configuration options specific to notices.

* `contentlimit`: max length of the plain-text content of a notice.
    Default is null, meaning to use the site-wide text limit.
    0 means no limit.

* `defaultscope`: default scope for notices. If null, the default
	scope depends on site/private. It's 1 if the site is private,
	0 otherwise. Set this value to override.

message
-------------------------------------------------------------------------------

Configuration options specific to messages.

* `contentlimit`: max length of the plain-text content of a message.
    Default is null, meaning to use the site-wide text limit.
    0 means no limit.

logincommand
-------------------------------------------------------------------------------

Configuration options for the login command.

* `disabled`: whether to enable this command. If enabled, users who send
    the text 'login' to the site through any channel will
    receive a link to login to the site automatically in return.
    Possibly useful for users who primarily use an XMPP or SMS
    interface and can't be bothered to remember their site
    password. Note that the security implications of this are
    pretty serious and have not been thoroughly tested. You
    should enable it only after you've convinced yourself that
    it is safe. Default is 'false'.

singleuser
-------------------------------------------------------------------------------

If an installation has only one user, this can simplify a lot of the
interface. It also makes the user's profile the root URL.

* `enabled` (boolean, default true): Whether to run in "single user mode".

* `nickname` (string, default null): nickname of the single user. If no nickname is
  specified, the site owner account will be used (if present).

robotstxt
-------------------------------------------------------------------------------

We put out a default robots.txt file to guide the processing of
Web crawlers. See http://www.robotstxt.org/ for more information
on the format of this file.

* `crawldelay`: if non-empty, this value is provided as the Crawl-Delay:
    for the robots.txt file. see <https://en.wikipedia.org/wiki/Robots_exclusion_standard#Crawl-delay_directive>
    for more information. Default is zero, no explicit delay.

* `disallow`: Array of (virtual) directories to disallow. Default is 'main',
    'search', 'message', 'settings', 'admin'. Ignored when site
    is private, in which case the entire site ('/') is disallowed.

api
---

Options for the Twitter-like API.

* `realm`: HTTP Basic Auth realm (see http://tools.ietf.org/html/rfc2617
    for details). Some third-party tools like ping.fm want this to be
    'Identi.ca API', so set it to that if you want to. default = null,
    meaning 'something based on the site name'.

nofollow
--------

We optionally put 'rel="nofollow"' on some links in some pages. The
following configuration settings let you fine-tune how or when things
are nofollowed. See http://en.wikipedia.org/wiki/Nofollow for more
information on what 'nofollow' means.

* `subscribers`: whether to nofollow links to subscribers on the profile
    and personal pages. Default is true.

* `members`: links to members on the group page. Default true.

* `peopletag`: links to people listed in the peopletag page. Default true.

* `external`: external links in notices. One of three values: 'sometimes',
    'always', 'never'. If 'sometimes', then external links are not
    nofollowed on profile, notice, and favorites page. Default is
    'sometimes'.

url
---

These are some options for fine-tuning how and when the server will
shorten URLs.

* `shortener`: URL shortening service to use by default. Users can override
           individually. 'internal' by default.

* `maxurllength`: If an URL is strictly longer than this limit, it will be
           shortened. Note that the URL shortener service may return an
           URL longer than this limit. Defaults to 100. Users can
           override. If set to 0, all URLs will be shortened.

* `maxnoticelength`: If a notice is strictly longer than this limit, all
           URLs in the notice will be shortened. Users can override.
           -1 means the text limit for notices.

router
------

We use a router class for mapping URLs to code. This section controls
how that router works.

* `cache`: whether to cache the router in cache layers. Defaults to true,
    but may be set to false for developers (who might be actively
    adding pages, so won't want the router cached) or others who see
    strange behavior. You're unlikely to need this unless developing..

http
----

Settings for the HTTP client.

* `ssl_cafile`: location of the CA file for SSL. If not set, won't verify
	    SSL peers. Default unset.

* `curl`: Use cURL <http://curl.haxx.se/> for doing HTTP calls. You must
      have the PHP curl extension installed for this to work.

* `proxy_host`: Host to use for proxying HTTP requests. If unset, doesn't
	    do any HTTP proxy stuff. Default unset.

* `proxy_port`: Port to use to connect to HTTP proxy host. Default null.

* `proxy_user`: Username to use for authenticating to the HTTP proxy. Default null.

* `proxy_password`: Password to use for authenticating to the HTTP proxy. Default null.

* `proxy_auth_scheme`: Scheme to use for authenticating to the HTTP proxy. Default null.

plugins
-------

* `default`: associative array mapping plugin name to array of arguments. To disable
	 a default plugin, unset its value in this array.

* `locale_path`: path for finding plugin locale files. In the plugin's directory
	     by default.

* `server`: Server to find static files for a plugin when the page is plain old HTTP.
	Defaults to site/server (same as pages). Use this to move plugin CSS and
	JS files to a CDN.

* `sslserver`: Server to find static files for a plugin when the page is HTTPS. Defaults
	   to site/server (same as pages). Use this to move plugin CSS and JS files
	   to a CDN.

* `path`: Path to the plugin files. defaults to site/path + '/plugins/'. Expects that
      each plugin will have a subdirectory at plugins/NameOfPlugin. Change this
      if you're using a CDN.

* `sslpath`: Path to use on the SSL server. Same as plugins/path.

performance
-----------

* `high`: if you need high performance, or if you're seeing bad
      performance, set this to true. It will turn off some high-intensity code from
      the site.

oldschool
---------

* `enabled`: enable certain old-style user settings options, like stream-only mode,
	 conversation trees, and nicknames in streams. Off by default, and
	 may not be well supported in future versions.


code:
Plugins
=======

GNU social supports a simple but
powerful plugin architecture. Important events in the code are named,
like 'StartNoticeSave', and other software can register interest
in those events. When the events happen, the other software is called
and has a choice of accepting or rejecting the events.

In the simplest case, you can add a function to config.php and use the
Event::addHandler() function to hook an event:

    function AddMyWebsiteLink($action)
    {
        $action->menuItem('http://mywebsite.net/', _('My web site'), _('Example web link'));
        return true;
    }

    Event::addHandler('EndPrimaryNav', 'AddMyWebsiteLink');

This adds a menu item to the end of the main navigation menu. You can
see the list of existing events, and parameters that handlers must
implement, in EVENTS.txt.

The Plugin class in lib/plugin.php makes it easier to write more
complex plugins. Sub-classes can just create methods named
'onEventName', where 'EventName' is the name of the event (case
matters!). These methods will be automatically registered as event
handlers by the Plugin constructor (which you must call from your own
class's constructor).

Several example plugins are included in the plugins/ directory. You
can enable a plugin with the following line in config.php:

    addPlugin('Example', array('param1' => 'value1',
                               'param2' => 'value2'));

This will look for and load files named 'ExamplePlugin.php' or
'Example/ExamplePlugin.php' either in the plugins/ directory (for
plugins that ship with GNU social) or in the local/ directory (for
plugins you write yourself or that you get from somewhere else) or
local/plugins/.

Plugins are documented in their own directories.

license: mit


code:
#Simple way to Webfinger enable your domain -- needs PHP

##Step 1

Put the 'dot-well-known' on your website, so it loads at:

     https://another_cool.org/.well-known/

(Remember the . at the beginning of this one, which is common practice
for "hidden" files and why we have renamed it "dot-")

## Step 2

Edit the .well-known/webfinger/index.php file and replace "https://www.example.org/gnusocial/index.php" with the domain name
you're hosting the .well-known handler on.


code:
<?php

// FIXME: REPLACE          \/ here
define('MY_GNUSOCIAL', 'https://www.example.org/gnusocial/index.php');

/**
 * This is a general solution for when you can't have your GNU social instance in the domain root and for when you want to
 * socialfy from another domain.
 */

// From https://www.php.net/manual/en/function.getallheaders.php#84262 (joyview at gmail dot com)
if (!function_exists('getallheaders')) {
    function getallheaders()
    {
        $headers = [];
        foreach ($_SERVER as $name => $value) {
            if (substr($name, 0, 5) == 'HTTP_') {
                $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
            }
        }
        return $headers;
    }
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, getallheaders());
curl_setopt($ch, CURLOPT_URL, MY_GNUSOCIAL . str_replace('webfinger/', 'webfinger', $_SERVER['REQUEST_URI']));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
$response = curl_exec($ch);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$body = substr($response, $header_size);
// From https://stackoverflow.com/a/10590242 (c.hill)
function get_headers_from_curl_response($response)
{
    $headers = array();

    $header_text = substr($response, 0, strpos($response, "\r\n\r\n"));

    foreach (explode("\r\n", $header_text) as $i => $line) {
        if ($i === 0) {
            $headers['http_code'] = $line;
        } else {
            list($key, $value) = explode(': ', $line);

            $headers[$key] = $value;
        }
    }

    return $headers;
}
$headers = get_headers_from_curl_response($response);
foreach ($headers as $name => $value) {
    header("{$name}: $value");
}
echo $body;
curl_close($ch);


code:
Upgrading
=========

GNU social 1.1.x to GNU social 1.2.x
------------------------------------

If you are tracking the GNU social git repository, we currently recommend
using the "master" branch (or nightly if you want to use latest features)
and follow this procedure:

0. Backup your data. The StatusNet upgrade discussions below have some
    guidelines to back up the database and files (mysqldump and rsync).

    MAKE SURE YOU ARE THE SAME USER THAT RUNS THE PHP FILES WHILE PERFORMING
    THE COMMANDS BELOW (I usually prepend the commands with 'sudo -u social')

1. Stop your queue daemons (you can run this command even if you do not
    use the queue daemons):
    $ bash scripts/stopdaemons.sh

2. Run the command to fetch the latest sourcecode:
    $ git pull

    If you are not using git we recommend following the instructions below
    for upgrading "StatusNet 1.1.x to GNU social 1.2.x" as they are similar.

3. Run the upgrade script:
    $ php scripts/upgrade.php

   The upgrade script will likely take a long time because it will
    upgrade the tables to another character encoding and make other
    automated upgrades. Make sure it ends without errors. If you get
    errors, create a new task on https://git.gnu.io/gnu/gnu-social/issues

4. Start your queue daemons again (you can run this command even if you
    do not use the queue daemons):
    $ bash scripts/startdaemons.sh

5. Report any issues at https://git.gnu.io/gnu/gnu-social/issues

If you are using ssh keys to log in to your server, you can make this
procedure pretty painless (assuming you have automated backups already).
Make sure you "cd" into the correct directory (in this case "htdocs")
and use the correct login@hostname combo:
    $ ssh social@domain.example 'cd htdocs
            && bash scripts/stopdaemons.sh
            && git pull
            && time php scripts/upgrade.php
            && bash scripts/startdaemons.sh'

StatusNet 1.1.x to GNU social 1.2.x
-----------------------------------

We cannot support migrating from any other version of StatusNet than
1.1.1. If you are running a StatusNet version lower than this, please
follow the upgrade procedures for each respective StatusNet version.

You are now running StatusNet 1.1.1 and want to migrate to GNU social
1.2.x. Beware there may be changes in minimum required version of PHP
and the modules required, so review the INSTALL file (php5-intl is a
newly added dependency for example).

* Before you begin: Make backups. Always make backups. Of your entire
directory structure and the database too. All tables. All data. Alles.

0. Make a backup of everything. To backup the database, you can use a
variant of this command (you will be prompted for the database password):
    $ mysqldump -u dbuser -p dbname > social-backup.sql

1. Stop your queue daemons 'bash scripts/stopdaemons.sh' should do it.
    Not everyone runs queue daemons, but the above command won't hurt.

2. Unpack your GNU social code to a fresh directory. You can do this
    by cloning our git repository:
    $ git clone https://git.gnu.io/gnu/gnu-social.git gnusocial

3. Synchronize your local files to the GNU social directory. These
    will be the local files such as avatars, config and files:

        avatar/*
        file/*
        local/*
        .htaccess
        config.php

    This command will point you in the right direction on how to do it:
    $ rsync -avP statusnet/{.htaccess,avatar,file,local,config.php} gnusocial/

4. Replace your old StatusNet directory with the new GNU social
    directory in your webserver root.

5. Run the upgrade script: 'php scripts/upgrade.php'
   The upgrade script will likely take a long time because it will
    upgrade the tables to another character encoding and make other
    automated upgrades. Make sure it ends without errors. If you get
    errors, create a new task on https://git.gnu.io/gnu/gnu-social/issues

6. Start your queue daemons: 'bash scripts/startdaemons.sh'

7. Report any issues at https://git.gnu.io/gnu/gnu-social/issues


code:
### GNU social "fancy URL" setup
#
#   Change the "RewriteBase" in the new .htaccess file to be the URL path
#       to your GNU Social installation on your server. Typically this will
#       be the path to your GNU Social directory relative to your Web root.
#       If you are installing it in the root directory, leave it as '/'.
#
#   If it doesn't work, double-check that AllowOverride for the GNU Social
#       directory is 'All' in your Apache configuration file. This can be
#       * /etc/apache2/apache2.conf (generic)
#       * /etc/apache2/sites-available/default(on Debian and Ubuntu)
#       * ...many other variations depending on distribution...
#
#   See the Apache documentation for .htaccess files for more details:
#       https://httpd.apache.org/docs/2.4/howto/htaccess.html
#
#   Also, check that mod_rewrite is installed and enabled:
#       https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html

<IfModule mod_rewrite.c>
  RewriteEngine On

  # NOTE: change this to your actual GNU social base URL path,
  # minus the domain part:
  #
  #   https://social.example.com/        => /
  #   https://example.com/social/ => /social/
  #
  RewriteBase /
  #RewriteBase /mublog/

  ## Uncomment these if having trouble with API authentication
  ## when PHP is running in CGI or FastCGI mode.
  #
  #RewriteCond %{HTTP:Authorization} ^(.*)
  #RewriteRule ^(.*) - [E=HTTP_AUTHORIZATION:%1]

  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule (.*) index.php?p=$1 [L,QSA]

  ## You can also use PATHINFO by using this RewriteRule instead:
  # RewriteRule (.*) index.php/$1 [L,QSA]
</IfModule>

# Enable X-Sendfile if available. Still needs to be enabled in the config
<IfModule mod_xsendfile.c>
  XSendFile On
</IfModule>

<FilesMatch "\.(ini)">
    <IfVersion < 2.3>
        Order allow,deny
        Deny from all
    </IfVersion>
    <IfVersion >= 2.3>
        Require all denied
    </IfVersion>
</FilesMatch>


code:
# This is completely optional, but if you're running a site with
# ssl="always" configured, then you might as well redirect any of
# your stray HTTP visitors to HTTPS.
#
#$HTTP["scheme"] == "http" {
#  $HTTP["host"] =~ "^(social\.example\.com)$" {
#    url.redirect = ( "^\/?(.*)" => "https://%1/$1" )
#    server.name                 = "%1"
#  }
#}

# If you're using vhosts, you should have per-vhost server.document-root
#   settings too! Read how in the respective alternative vhost modules.
#$HTTP["host"] =~ "^social\.example\.com$" {

#    NOTE: configure fastcgi/cgi/fpm here if you're using per-user cgi/fpm
#    fastcgi.server += ( ".php" =>
#      ( "localhost" => (
#        "host" => "127.0.0.1",
#        "port" => "9000"
#      ))
#    )

    dir-listing.activate = "disable"

# Make sure "mod_rewrite" is enabled in server.modules
    url.rewrite-if-not-file = ( "^/(.*)$" => "/index.php/$1" )
#}


code:
server {
    listen [::]:80;
    listen 80;

# FIXME: Change domain name here (and also make sure you do the same in the next 'server' section)
    server_name social.example.org;

# redirect all traffic to HTTPS
    rewrite ^ https://$host$request_uri? permanent;
}

server {
# HTTPS is mandatory on GNU social unless you are using Tor network. Seriously.
# Set it up with a cert (any cert) before you run the install.
    listen [::]:443 ssl http2;
    listen 443 ssl http2;

# Root
# FIXME: Change the path below to where you installed GNU social (GNU social's root + /public)
    root /var/www/gnusocial/public;

# Server name
# FIXME: Change "social.example.org" to your site's domain name
    server_name social.example.org;

# SSL
# FIXME: Change the paths to setup your SSL key/cert. See https://cipherli.st/ for more information
    ssl_certificate       ssl/certs/social.example.org.crt;
    ssl_certificate_key   ssl/private/social.example.org.key;

# Index
    index index.php;

# X-Accel/X-Sendfile. Still needs to be enabled in the config
    location /file {
        internal;
        # FIXME: Change "/path/to/gnusocial/root/" to the folder where
        # attachments are stored (normally the same as the site root)
        root /path/to/gnusocial/root/;
    }

# PHP
    location ~ ^/(index|install)\.php(/.*)?$ {
    #location ^~ /index.php {
        include fastcgi_params;
        include snippets/fastcgi-php.conf;

        fastcgi_pass unix:/run/php/php-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $request_filename;
    }

# Don't allow any PHP file other than index.php to be executed
# This will ensure that nor config.php nor plugin files with eventual hardcoded security information are downloadable
# And this is better than allowing php files to be executed in case of forgotten `if (!defined('GNUSOCIAL')) { exit(1); }`
    location ~ \.php$ {
        deny all;
    }

# Location
    location / {
        try_files $uri $uri/ @index_handler;
    }

# Fancy URLs
    error_page 404 @index_handler;
    location @index_handler {
        rewrite ^(.*)$ /index.php?p=$1 last;
    }

# Restrict access that is unnecessary anyway
    location ~ /\.(ht|git) {
        deny all;
    }

#
# Hardening (optional)
#
#    add_header Strict-Transport-Security "max-age=15768000; preload;";
#    add_header X-Content-Type-Options nosniff;
#    add_header Referrer-Policy strict-origin-when-cross-origin;
#    add_header Content-Security-Policy "default-src 'self' 'unsafe-inline'; frame-ancestors 'self'; form-action 'self'; style-src 'self' 'unsafe-inline'; img-src * blob: data:;";
#    add_header X-Permitted-Cross-Domain-Policies none;
#    add_header X-Robots-Tag all; # Not really hardening, just here for strictness purposes
#
#    client_max_body_size 15M;
#    client_body_buffer_size 128k;
#    gzip_vary on;
#
#    location ~* \.(?:css|js|woff|svg|gif|png|webp|ttf|ico|jpe?g)$ {
#        gzip on;
#        gzip_comp_level 4;
#        add_header Cache-Control "public";
#        expires 30d;
#        access_log off;
#        log_not_found off;
#    }
}


code:
# Versioning

## Release cycle
We follow Semantic Versioning as defined on [https://semver.org/](https://semver.org).

The GNU social platform has a monthly release cycle. That  is, we only increment the version number on day 1 of each month.

For GNU social plugins, we increment version number by commit. Plugins update have a propagation of the same type in the
GNU social's monthly version bump.

If we have various patch type updates in a month, we only bump it by one in the end of the month. If in the same month
we have a minor too, we will only bump the minor value.

# Lifecycle

GNU social has 'dev', 'alpha', 'beta', 'rc' and 'release' cycles. We usually are in `dev` during summer. When we finish a `dev` cycle we release an `alpha` (`dev`s aren't tagged as releases). From `alpha` to `release` it depends on how perfect GNU social is after the end of the `dev` cycle. But we use the number after `alpha` instead of `patch` number for small bug fixes when in this cycle. When we finally go from a `r`elease `c`andidate to a `release`, we party... and we use semver for all the small changes until we start working in another `dev` cycle (usually on another summer).


code:
TABLE OF CONTENTS
=================
* Prerequisites
    - PHP modules
    - Better performance
* Installation
    - Getting it up and running
    - Fancy URLs
    - Themes
    - Private
* Extra features
    - Sphinx
    - SMS
    - Translation
    - Queues and daemons
* After installation
    - Backups
    - Upgrading
* Additional configuration

Prerequisites
=============

PHP modules
-----------

The following software packages are *required* for this software to
run correctly.

- PHP 7+        PHP7.x is also supported.
- MariaDB 5+    MariaDB 10.x is also supported.
- Web server    Apache, lighttpd and nginx will all work. CGI mode is
                recommended and also some variant of 'suexec' (or a
                proper setup php-fpm pool)
                NOTE: mod_rewrite or its equivalent is extremely useful.

Your PHP installation must include the following PHP extensions for a
functional setup of GNU social:

- openssl       (compiled in for Debian, enabled manually in Arch Linux)
- php-curl      Fetching files by HTTP.
- php-exif      Exchangeable image information.
- php-gd        Image manipulation (scaling).
- php-intl      Internationalization support (transliteration et al).
- php-json      For WebFinger lookups and more.
- php-mbstring  String manipulation
- php-mysql     The native driver for MariaDB connections.
- php-gmp       For Salmon signatures (part of OStatus)
- php-bcmath    Arbitrary Precision Mathematics
- php-opcache   Improved PHP performance by precompilation
- php-readline  For interactive scripts
- php-xml       XML parser
- php-ds        Faster data structures

NOTE: Some distros require manual enabling in the relevant php.ini for some modules.

Better performance
------------------

For some functionality, you will also need the following extensions:

- opcache       Improves performance a _lot_. Included in PHP, must be
                enabled manually in php.ini for most distributions. Find
                and set at least:  opcache.enable=1
- mailparse     Efficient parsing of email requires this extension.
                Submission by email or SMS-over-email uses this.
- sphinx        A client for the sphinx server, an alternative to MySQL
                or Postgresql fulltext search. You will also need a
                Sphinx server to serve the search queries.
- gettext       For multiple languages. Default on many PHP installs;
                will be emulated if not present.
- exif          For thumbnails to be properly oriented.
- php-ds        For faster data structures; will be emulated if not present.

You may also experience better performance from your site if you configure
a PHP cache/accelerator. Most distributions come with "opcache" support.
Enable it in your php.ini where it is documented together with its settings.

Installation
============

Getting it up and running
-------------------------

Installing the basic GNU Social web component is relatively easy,
especially if you've previously installed PHP/MariaDB packages.

1. Unpack the tarball you downloaded on your Web server. Usually a
   command like this will work:

       tar zxf gnusocial-*.tar.gz

   ...which will make a gnusocial-x.y.z subdirectory in your current
   directory. (If you don't have shell access on your Web server, you
   may have to unpack the tarball on your local computer and FTP the
   files to the server.)

2. Move the tarball to a directory of your choosing in your Web root
   directory. Usually something like this will work:

       mv gnusocial-x.y.z /var/www/gnusocial

   This will often make your GNU Social instance available in the gnusocial
   path of your server, like "http://example.net/gnusocial". "social" or
   "blog" might also be good path names. If you know how to configure
   virtual hosts on your web server, you can try setting up
   "http://social.example.net/" or the like.

   If you have "rewrite" support on your webserver, and you should,
   then please enable this in order to make full use of your site. This
   will enable "Fancy URL" support, which you can read more about if you
   scroll down a bit in this document.

3. Make your target directory writeable by the Web server, please note
   however that 'a+w' will give _all_ users write access and securing the
   webserver is not within the scope of this document.

       chmod a+w /var/www/gnusocial/

   On some systems, this will work as a more secure alternative:

       chgrp www-data /var/www/gnusocial/
       chmod g+w /var/www/gnusocial/

   If your Web server runs as another user besides "www-data", try
   that user's default group instead. As a last resort, you can create
   a new group like "gnusocial" and add the Web server's user to the group.

4. Create a database to hold your site data. Something like this
   should work (you will be prompted for your database password):

       mysqladmin -u "root" -p create social

   Note that GNU Social should have its own database; you should not share
   the database with another program. You can name it whatever you want,
   though.

   (If you don't have shell access to your server, you may need to use
   a tool like phpMyAdmin to create a database. Check your hosting
   service's documentation for how to create a new MariaDB database.)

5. Create a new database account that GNU Social will use to access the
   database. If you have shell access, this will probably work from the
   MariaDB shell:

       GRANT ALL on social.*
       TO 'social'@'localhost'
       IDENTIFIED BY 'agoodpassword';

   You should change the user identifier 'social' and 'agoodpassword'
   to your preferred new database username and password. You may want to
   test logging in to MariaDB as this new user.

6. In a browser, navigate to the GNU Social install script; something like:

       https://social.example.net/install.php

   Enter the database connection information and your site name. The
   install program will configure your site and install the initial,
   almost-empty database.

7. You should now be able to navigate to your social site's main directory
   and see the "Public Timeline", which will probably be empty. You can
   now register new user, post some notices, edit your profile, etc.

Fancy URLs
----------

By default, GNU Social will use URLs that include the main PHP program's
name in them. For example, a user's home profile might be found at either
of these URLS depending on the webserver's configuration and capabilities:

    https://social.example.net/index.php/fred
    https://social.example.net/index.php?p=fred

It's possible to configure the software to use fancy URLs so it looks like
this instead:

    https://social.example.net/fred

These "fancy URLs" are more readable and memorable for users. To use
fancy URLs, you must either have Apache 2.x with .htaccess enabled and
mod_rewrite enabled, -OR- know how to configure "url redirection" in
your server (like lighttpd or nginx).

1. See the instructions for each respective webserver software:
    * For Apache, inspect the "htaccess.sample" file and save it as
        ".htaccess" after making any necessary modifications. Our sample
        file is well commented.
    * For lighttpd, inspect the lighttpd.conf.example file and apply the
        appropriate changes in your virtualhost configuration for lighttpd.
    * For nginx, inspect the nginx.conf.sample file and apply the appropriate
        changes.
    * For other webservers, we gladly accept contributions of
        server configuration examples.

2. Assuming your webserver is properly configured and have its settings
    applied (remember to reload/restart it), you can add this to your
    GNU social's config.php file:
       $config['site']['fancy'] = true;

You should now be able to navigate to a "fancy" URL on your server,
like:

    https://social.example.net/main/register

Themes
------

As of right now, your ability change the theme is limited to CSS
stylesheets and some image files; you can't change the HTML output,
like adding or removing menu items, without the help of a plugin.

You can choose a theme using the $config['site']['theme'] element in
the config.php file. See below for details.

You can add your own theme by making a sub-directory of the 'theme'
subdirectory with the name of your theme. Each theme can have the
following files:

display.css: a CSS2 file for "default" styling for all browsers.
logo.png: a logo image for the site.
default-avatar-profile.png: a 96x96 pixel image to use as the avatar for
users who don't upload their own.
default-avatar-stream.png: Ditto, but 48x48. For streams of notices.
default-avatar-mini.png: Ditto ditto, but 24x24. For subscriptions
listing on profile pages.

You may want to start by copying the files from the default theme to
your own directory.

Private
-------

A GNU social node can be configured as "private", which means it will not
federate with other nodes in the network. It is not a recommended method
of using GNU social and we cannot at the current state of development
guarantee that there are no leaks (what a public network sees as features,
private sites will likely see as bugs).

Private nodes are however an easy way to easily setup collaboration and
image sharing within a workgroup or a smaller community where federation
is not a desired feature. Also, it is possible to change this setting and
instantly gain full federation features.

Access to file attachments can also be restricted to logged-in users only:

1. Add a directory outside the web root where your file uploads will be
   stored. Use this command as an initial guideline to create it:

       mkdir /var/www/gnusocial-files

2. Make the file uploads directory writeable by the web server. An
   insecure way to do this is (to do it properly, read up on UNIX file
   permissions and configure your webserver accordingly):

       chmod a+x /var/www/gnusocial-files

3. Tell GNU social to use this directory for file uploads. Add a line
   like this to your config.php:

       $config['attachments']['dir'] = '/var/www/gnusocial-files';

Extra features
==============

Sphinx
------

To use a Sphinx server to search users and notices, you'll need to
enable the SphinxSearch plugin. Add to your config.php:

    addPlugin('SphinxSearch');
    $config['sphinx']['server'] = 'searchhost.local';

You also need to install, compile and enable the sphinx pecl extension for
php on the client side, which itself depends on the sphinx development files.

See plugins/SphinxSearch/README for more details and server setup.

SMS
---

StatusNet supports a cheap-and-dirty system for sending update messages
to mobile phones and for receiving updates from the mobile. Instead of
sending through the SMS network itself, which is costly and requires
buy-in from the wireless carriers, it simply piggybacks on the email
gateways that many carriers provide to their customers. So, SMS
configuration is essentially email configuration.

Each user sends to a made-up email address, which they keep a secret.
Incoming email that is "From" the user's SMS email address, and "To"
the users' secret email address on the site's domain, will be
converted to a notice and stored in the DB.

For this to work, there *must* be a domain or sub-domain for which all
(or most) incoming email can pass through the incoming mail filter.

1. Run the SQL script carrier.sql in your StatusNet database. This will
   usually work:

       mysql -u "statusnetuser" --password="statusnetpassword" statusnet < db/carrier.sql

   This will populate your database with a list of wireless carriers
   that support email SMS gateways.

2. Make sure the maildaemon.php file is executable:

       chmod +x scripts/maildaemon.php

   Note that "daemon" is kind of a misnomer here; the script is more
   of a filter than a daemon.

2. Edit /etc/aliases on your mail server and add the following line:

       *: /path/to/statusnet/scripts/maildaemon.php

3. Run whatever code you need to to update your aliases database. For
   many mail servers (Postfix, Exim, Sendmail), this should work:

       newaliases

   You may need to restart your mail server for the new database to
   take effect.

4. Set the following in your config.php file:

       $config['mail']['domain'] = 'yourdomain.example.net';

Translations
------------

For info on helping with translations, see the platform currently in use
for translations: https://www.transifex.com/projects/p/gnu-social/

Translations use the gettext system <http://www.gnu.org/software/gettext/>.
If you for some reason do not wish to sign up to the Transifex service,
you can review the files in the "locale/" sub-directory of GNU social.
Each plugin also has its own translation files.

To get your own site to use all the translated languages, and you are
tracking the git repo, you will need to install at least 'gettext' on
your system and then run:
    $ make translations

Queues and daemons
------------------

Some activities that StatusNet needs to do, like broadcast OStatus, SMS,
XMPP messages and TwitterBridge operations, can be 'queued' and done by
off-line bots instead.

Two mechanisms are available to achieve offline operations:

* New embedded OpportunisticQM plugin, which is enabled by default
* Legacy queuedaemon script, which can be enabled via config file.

### OpportunisticQM plugin

This plugin is enabled by default. It tries its best to do background
jobs during regular HTTP requests, like API or HTML pages calls.

Since queueing system is enabled by default, notices to be broadcasted
will be stored, by default, into DB (table queue_item).

Whenever it has time, OpportunisticQM will try to handle some of them.

This is a good solution whether you:

* have no access to command line (shared hosting)
* do not want to deal with long-running PHP processes
* run a low traffic GNU social instance

In other case, you really should consider enabling the queuedaemon for
performance reasons. Background daemons are necessary anyway if you wish
to use the Instant Messaging features such as communicating via XMPP.

### queuedaemon

If you want to use legacy queuedaemon, you must be able to run
long-running offline processes, either on your main Web server or on
another server you control. (Your other server will still need all the
above prerequisites, with the exception of Apache.) Installing on a
separate server is probably a good idea for high-volume sites.

1. You'll need the "CLI" (command-line interface) version of PHP
   installed on whatever server you use.

   Modern PHP versions in some operating systems have disabled functions
   related to forking, which is required for daemons to operate. To make
   this work, make sure that your php-cli config (/etc/php5/cli/php.ini)
   does NOT have these functions listed under 'disable_functions':

       * pcntl_fork, pcntl_wait, pcntl_wifexited, pcntl_wexitstatus,
         pcntl_wifsignaled, pcntl_wtermsig

   Other recommended settings for optimal performance are:
       * mysqli.allow_persistent = On
       * mysqli.reconnect = On

2. If you're using a separate server for queues, install StatusNet
   somewhere on the server. You don't need to worry about the
   .htaccess file, but make sure that your config.php file is close
   to, or identical to, your Web server's version.

3. In your config.php files (on the server where you run the queue
    daemon), set the following variable:

       $config['queue']['daemon'] = true;

   You may also want to look at the 'Queues and Daemons' section in
   this file for more background processing options.

4. On the queues server, run the command scripts/startdaemons.sh.

This will run the queue handlers:

* queuedaemon.php - polls for queued items for inbox processing and
  pushing out to OStatus, SMS, XMPP, etc.
* imdaemon.php - if an IM plugin is enabled (like XMPP)
* other daemons, like TwitterBridge ones, that you may have enabled

These daemons will automatically restart in most cases of failure
including memory leaks (if a memory_limit is set), but may still die
or behave oddly if they lose connections to the XMPP or queue servers.

It may be a good idea to use a daemon-monitoring service, like 'monit',
to check their status and keep them running.

All the daemons write their process IDs (pids) to /var/run/ by
default. This can be useful for starting, stopping, and monitoring the
daemons. If you are running multiple sites on the same machine, it will
be necessary to avoid collisions of these PID files by setting a site-
specific directory in config.php:

       $config['daemon']['piddir'] = __DIR__ . '/../run/';

It is also possible to use a STOMP server instead of our kind of hacky
home-grown DB-based queue solution. This is strongly recommended for
best response time, especially when using XMPP.

After installation
==================

Backups
-------

There is no built-in system for doing backups in GNU social. You can make
backups of a working StatusNet system by backing up the database and
the Web directory. To backup the database use mysqldump <https://mariadb.com/kb/en/mariadb/mysqldump/>
and to backup the Web directory, try tar.

Upgrading
---------

Upgrading is strongly recommended to stay up to date with security fixes
and new features. For instructions on how to upgrade GNU social code,
please see the UPGRADE file.

Additional configuration
------------------------

Please refer to DOCUMENTATION/SYSTEM_ADMINISTRATORS/CONFIGURE for information.


code:
# Warning: do not transform tabs to spaces in this file.

all : translations

core_mo = $(patsubst %.po,%.mo,$(wildcard locale/*/LC_MESSAGES/statusnet.po))
plugin_mo = $(patsubst %.po,%.mo,$(wildcard plugins/*/locale/*/LC_MESSAGES/*.po))

translations : $(core_mo) $(plugin_mo)

upgrade :
	php scripts/upgrade.php

clean :
	rm -f $(core_mo) $(plugin_mo)

updatepo :
	php scripts/update_po_templates.php --all

%.mo : %.po
	msgfmt -o $@ $<

path: Makefile


code:
# GNU social 2.0.x
(c) 2010-2019 Free Software Foundation, Inc

This is the README file for GNU social, the free
software social networking platform. It includes
general information about the software and the
project.

The file INSTALL.md has useful instructions on how to
install this software.

System administrators may find the `DOCUMENTATION/SYSTEM_ADMINISTRATORS`
directory useful, namely:

- upgrade_from: upgrading from different software
- CONFIGURE.md: configuration options in gruesome detail.
- PLUGINS.md: how to install and configure plugins.

Developers may find the `DOCUMENTATION/DEVELOPERS` directory useful.

## About

GNU social is a free social networking
platform. It helps people in a community, company
or group to exchange short status updates, do
polls, announce events, or other social activities
(and you can add more!). Users can choose which
people to "follow" and receive only their friends'
or colleagues' status messages. It provides a
similar service to proprietary social network sites,
but is much more awesome.

With a little work, status messages can be sent to
mobile phones, instant messenger programs (using
XMPP), and specially-designed desktop clients that
support the Twitter API.

GNU social supports open standards (such as OStatus
<https://www.w3.org/community/ostatus/>) that lets users in
different networks follow each other. It enables a
distributed social network spread all across the
Web.

GNU social was originally developed as "StatusNet" by
StatusNet, Inc. with Evan Prodromou as lead developer.

It is shared with you in hope that you too make an
service available to your users. To learn more,
please see the Open Software Service Definition
1.1: <http://www.opendefinition.org/ossd>

### License

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, in the file "COPYING".  If not, see
<http://www.gnu.org/licenses/>.

    IMPORTANT NOTE: The GNU Affero General Public License (AGPL) has
    *different requirements* from the "regular" GPL. In particular, if
    you make modifications to the GNU social source code on your server,
    you *MUST MAKE AVAILABLE* the modified version of the source code
    to your users under the same license. This is a legal requirement
    of using the software, and if you do not wish to share your
    modifications, *YOU MAY NOT INSTALL GNU SOCIAL*.

Documentation in the /doc-src/ directory is available under the
Creative Commons Attribution 3.0 Unported license, with attribution to
"GNU social". See <http://creativecommons.org/licenses/by/3.0/> for details.

CSS and images in the /theme/ directory are available under the
Creative Commons Attribution 3.0 Unported license, with attribution to
"GNU social". See <http://creativecommons.org/licenses/by/3.0/> for details.

Our understanding and intention is that if you add your own theme that
uses only CSS and images, those files are not subject to the copyleft
requirements of the Affero General Public License 3.0. See
<http://wordpress.org/news/2009/07/themes-are-gpl-too/>. This is not
legal advice; consult your lawyer.

Additional library software has been made available in the 'extlib'
directory. All of it is Free Software and can be distributed under
liberal terms, but those terms may differ in detail from the AGPL's
particulars. See each package's license file in the extlib directory
for additional terms.

Refer to COPYING.md for full text of the software license..

### Troubleshooting

The primary output for GNU social is syslog,
unless you configured a separate logfile. This is
probably the first place to look if you're getting
weird behaviour from GNU social.

If you're tracking the unstable version of
GNU social in the git repository (see below), and you
get a compilation error ("unexpected T_STRING") in
the browser, check to see that you don't have any
conflicts in your code.

### Unstable version

If you're adventurous or impatient, you may want
to install the development version of GNU social.
To get it, use the git version control tool
<http://git-scm.com/> like so:

    git clone git@notabug.org:diogo/gnu-social.git

In the current phase of development it is probably
recommended to use git as a means to stay up to date
with the source code. You can choose between these
branches:
* 1.20.x    "oldstable", few updates, well tested coded
* master    "stable", usually working well
* nightly   "testing", most updates, not always working as expected

To keep it up-to-date, use `git pull`. Watch for conflicts!

As in any upgrade, do __not__ forget to run `/scripts/upgrade.php`.

## Further information

There are several ways to get more information about GNU social.

* The #social IRC channel on freenode.net <https://www.freenode.net/>.
* The unofficial XMPP room linked to IRC on <xmpp:gnusocial@conference.bka.li>
* The GNU social website <https://gnu.io/social/>

* GNU social has a bug tracker for any defects you may find, or ideas for
  making things better. <https://notabug.org/diogo/gnu-social/issues>
* Patches are welcome, preferrably to our repository on notabug.org. <https://notabug.org/diogo/gnu-social>

## Credits

An incomplete list of developers who've worked on GNU social,
or its predecessors StatusNet and Free Social has been made available
in `CREDITS.md`.

### Current team

* Matt Lee
* Mikael Nordfeldth
* Diogo Cordeiro
* Bruno Casteleiro
* Miguel Dantas
* Alexei Sorokin


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Site access administration panel
 *
 * PHP version 5
 *
 * LICENCE: 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/>.
 *
 * @category  Settings
 * @package   StatusNet
 * @author    Zach Copley <zach@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('GNUSOCIAL')) { exit(1); }

/**
 * Administer site access settings
 *
 * @category Admin
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class AccessadminpanelAction extends AdminPanelAction
{
    /**
     * Returns the page title
     *
     * @return string page title
     */
    function title()
    {
        // TRANS: Page title for Access admin panel that allows configuring site access.
        return _('Access');
    }

    /**
     * Instructions for using this form.
     *
     * @return string instructions
     */
    function getInstructions()
    {
        // TRANS: Page notice.
        return _('Site access settings');
    }

    /**
     * Show the site admin panel form
     *
     * @return void
     */
    function showForm()
    {
        $form = new AccessAdminPanelForm($this);
        $form->show();
        return;
    }

    /**
     * Save settings from the form
     *
     * @return void
     */
    function saveSettings()
    {
        static $booleans = array('site' => array('private', 'inviteonly', 'closed'),
                                 'public' => array('localonly'));

        foreach ($booleans as $section => $parts) {
            foreach ($parts as $setting) {
                $values[$section][$setting] = ($this->boolean($setting)) ? 1 : 0;
            }
        }

        $config = new Config();

        $config->query('BEGIN');

        foreach ($booleans as $section => $parts) {
            foreach ($parts as $setting) {
                Config::save($section, $setting, $values[$section][$setting]);
            }
        }

        $config->query('COMMIT');

        return;
    }
}

class AccessAdminPanelForm extends AdminForm
{
    /**
     * ID of the form
     *
     * @return int ID of the form
     */
    function id()
    {
        return 'form_site_admin_panel';
    }

    /**
     * class of the form
     *
     * @return string class of the form
     */
    function formClass()
    {
        return 'form_settings';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */
    function action()
    {
        return common_local_url('accessadminpanel');
    }

    /**
     * Data elements of the form
     *
     * @return void
     */
    function formData()
    {
        $this->out->elementStart('fieldset', array('id' => 'settings_admin_account_access'));
        // TRANS: Form legend for registration form.
        $this->out->element('legend', null, _('Registration'));
        $this->out->elementStart('ul', 'form_data');

        $this->li();
        // TRANS: Checkbox instructions for admin setting "Invite only".
        $instructions = _('Make registration invitation only.');
        // TRANS: Checkbox label for configuring site as invite only.
        $this->out->checkbox('inviteonly', _('Invite only'),
                             (bool) $this->value('inviteonly'),
                             $instructions);
        $this->unli();

        $this->li();
        // TRANS: Checkbox instructions for admin setting "Closed" (no new registrations).
        $instructions = _('Disable new registrations.');
        // TRANS: Checkbox label for disabling new user registrations.
        $this->out->checkbox('closed', _('Closed'),
                             (bool) $this->value('closed'),
                             $instructions);
        $this->unli();

        $this->out->elementEnd('ul');
        $this->out->elementEnd('fieldset');

        // Public access settings (login requirements for feeds etc.)
	    $this->out->elementStart('fieldset', array('id' => 'settings_admin_public_access'));
	    // TRANS: Form legend for registration form.
        $this->out->element('legend', null, _('Feed access'));
        $this->out->elementStart('ul', 'form_data');
        $this->li();
        // TRANS: Checkbox instructions for admin setting "Private".
        $instructions = _('Prohibit anonymous users (not logged in) from viewing site?');
        // TRANS: Checkbox label for prohibiting anonymous users from viewing site.
        $this->out->checkbox('private', _m('LABEL', 'Private'),
                             (bool) $this->value('private'),
                             $instructions);
        $this->unli();

        $this->li();
        // TRANS: Description of the full network notice stream views..
        $instructions = _('The full network view includes (public) remote notices which may be unrelated to local conversations.');
        // TRANS: Checkbox label for hiding remote network posts if they have not been interacted with locally.
        $this->out->checkbox('localonly', _('Restrict full network view to accounts'),
                             (bool) $this->value('localonly', 'public'),
                             $instructions);
        $this->unli();

        $this->out->elementEnd('ul');
        $this->out->elementEnd('fieldset');
    }

    /**
     * Action elements
     *
     * @return void
     */
    function formActions()
    {
        // TRANS: Button title to save access settings in site admin panel.
        $title = _('Save access settings.');
        // TRANS: Button text to save access settings in site admin panel.
        $this->out->submit('submit', _m('BUTTON', 'Save'), 'submit', null, $title);
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008-2010, StatusNet, Inc.
 *
 * Action to add a people tag to a user.
 *
 * 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/>.
 *
 * PHP version 5
 *
 * @category  Action
 * @package   StatusNet
 * @author    Shashi Gowda <connect2shashi@gmail.com>
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    exit(1);
}

require_once INSTALLDIR . '/lib/togglepeopletag.php';

/**
 *
 * Action to tag a profile with a single tag.
 *
 * Takes parameters:
 *
 *    - tagged: the ID of the profile being tagged
 *    - token: session token to prevent CSRF attacks
 *    - ajax: boolean; whether to return Ajax or full-browser results
 *    - peopletag_id: the ID of the tag being used
 *
 * Only works if the current user is logged in.
 *
 * @category  Action
 * @package   StatusNet
 * @author    Shashi Gowda <connect2shashi@gmail.com>
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */
class AddpeopletagAction extends Action
{
    var $user;
    var $tagged;
    var $peopletag;

    /**
     * Check pre-requisites and instantiate attributes
     *
     * @param Array $args array of arguments (URL, GET, POST)
     *
     * @return boolean success flag
     */
    function prepare(array $args = array())
    {
        parent::prepare($args);

        // CSRF protection

        $token = $this->trimmed('token');

        if (!$token || $token != common_session_token()) {
            // TRANS: Client error displayed when the session token does not match or is not given.
            $this->clientError(_('There was a problem with your session token.'.
                                 ' Try again, please.'));
        }

        // Only for logged-in users

        $this->user = common_current_user();

        if (empty($this->user)) {
            // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
            $this->clientError(_('Not logged in.'));
        }

        // Profile to subscribe to

        $tagged_id = $this->arg('tagged');

        $this->tagged = Profile::getKV('id', $tagged_id);

        if (empty($this->tagged)) {
            // TRANS: Client error displayed trying to perform an action related to a non-existing profile.
            $this->clientError(_('No such profile.'));
        }

        $id = $this->arg('peopletag_id');
        $this->peopletag = Profile_list::getKV('id', $id);

        if (empty($this->peopletag)) {
            // TRANS: Client error displayed trying to reference a non-existing list.
            $this->clientError(_('No such list.'));
        }

        return true;
    }

    /**
     * Handle request
     *
     * Does the tagging and returns results.
     *
     * @param Array $args unused.
     *
     * @return void
     */
    function handle()
    {
        // Throws exception on error
        $ptag = Profile_tag::setTag($this->user->id, $this->tagged->id,
                                $this->peopletag->tag);

        if (!$ptag) {
            $user = User::getKV('id', $id);
            if ($user) {
                $this->clientError(
                        // TRANS: Client error displayed when an unknown error occurs when adding a user to a list.
                        // TRANS: %s is a username.
                        sprintf(_('There was an unexpected error while listing %s.'),
                        $user->nickname));
            } else {
                // TRANS: Client error displayed when an unknown error occurs when adding a user to a list.
                // TRANS: %s is a profile URL.
                $this->clientError(sprintf(_('There was a problem listing %s. ' .
                                      'The remote server is probably not responding correctly. ' .
                                      'Please try retrying later.'), $this->profile->profileurl));
            }
        }
        if ($this->boolean('ajax')) {
            $this->startHTML('text/xml;charset=utf-8');
            $this->elementStart('head');
            // TRANS: Title after adding a user to a list.
            $this->element('title', null, _m('TITLE','Listed'));
            $this->elementEnd('head');
            $this->elementStart('body');
            $unsubscribe = new UntagButton($this, $this->tagged, $this->peopletag);
            $unsubscribe->show();
            $this->elementEnd('body');
            $this->endHTML();
        } else {
            $url = common_local_url('subscriptions',
                                    array('nickname' => $this->user->nickname));
            common_redirect($url, 303);
        }
    }
}


code:
<?php
/**
 * StatusNet - the 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/>.
 *
 * @category Actions
 * @package  Actions
 * @author   Adrian Lang <mail@adrianlang.de>
 * @author   Brenda Wallace <shiny@cpan.org>
 * @author   Brion Vibber <brion@pobox.com>
 * @author   Craig Andrews <candrews@integralblue.com>
 * @author   Evan Prodromou <evan@status.net>
 * @author   Jeffery To <jeffery.to@gmail.com>
 * @author   Meitar Moscovitz <meitarm@gmail.com>
 * @author   Mike Cochrane <mikec@mikenz.geek.nz>
 * @author   Robin Millette <millette@status.net>
 * @author   Sarven Capadisli <csarven@status.net>
 * @author   Siebrand Mazeland <s.mazeland@xs4all.nl>
 * @author   Zach Copley <zach@status.net>
 * @copyright 2009-2014 Free Software Foundation, Inc http://www.fsf.org
 * @license  GNU Affero General Public License http://www.gnu.org/licenses/
 * @link     http://status.net
 */

if (!defined('GNUSOCIAL')) { exit(1); }

class AllAction extends ShowstreamAction
{
    public function getStream()
    {
        if ($this->scoped instanceof Profile && $this->scoped->isLocal() && $this->scoped->getUser()->streamModeOnly()) {
            $stream = new InboxNoticeStream($this->target, $this->scoped);
        } else {
            $stream = new ThreadingInboxNoticeStream($this->target, $this->scoped);
        }

        return $stream;
    }

    function title()
    {
        if (!empty($this->scoped) && $this->scoped->sameAs($this->target)) {
            // TRANS: Title of a user's own start page.
            return _('Home timeline');
        } else {
            // TRANS: Title of another user's start page.
            // TRANS: %s is the other user's name.
            return sprintf(_("%s's home timeline"), $this->target->getBestName());
        }
    }

    function getFeeds()
    {
        return array(
            new Feed(Feed::JSON,
                common_local_url(
                    'ApiTimelineFriends', array(
                        'format' => 'as',
                        'id' => $this->target->getNickname()
                    )
                ),
                // TRANS: %s is user nickname.
                sprintf(_('Feed for friends of %s (Activity Streams JSON)'), $this->target->getNickname())),
            new Feed(Feed::RSS1,
                common_local_url(
                    'allrss', array(
                        'nickname' =>
                        $this->target->getNickname())
                ),
                // TRANS: %s is user nickname.
                sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->target->getNickname())),
            new Feed(Feed::RSS2,
                common_local_url(
                    'ApiTimelineFriends', array(
                        'format' => 'rss',
                        'id' => $this->target->getNickname()
                    )
                ),
                // TRANS: %s is user nickname.
                sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->target->getNickname())),
            new Feed(Feed::ATOM,
                common_local_url(
                    'ApiTimelineFriends', array(
                        'format' => 'atom',
                        'id' => $this->target->getNickname()
                    )
                ),
                // TRANS: %s is user nickname.
                sprintf(_('Feed for friends of %s (Atom)'), $this->target->getNickname()))
        );
    }

    function showEmptyListMessage()
    {
        // TRANS: Empty list message. %s is a user nickname.
        $message = sprintf(_('This is the timeline for %s and friends but no one has posted anything yet.'), $this->target->getNickname()) . ' ';

        if (common_logged_in()) {
            if ($this->target->id === $this->scoped->id) {
                // TRANS: Encouragement displayed on logged in user's empty timeline.
                // TRANS: This message contains Markdown links. Keep "](" together.
                $message .= _('Try subscribing to more people, [join a group](%%action.groups%%) or post something yourself.');
            } else {
                // TRANS: %1$s is user nickname, %2$s is user nickname, %2$s is user nickname prefixed with "@".
                // TRANS: This message contains Markdown links. Keep "](" together.
                $message .= sprintf(_('You can try to [nudge %1$s](../%2$s) from their profile or [post something to them](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->target->getNickname(), $this->target->getNickname(), '@' . $this->target->getNickname());
            }
        } else {
            // TRANS: Encouragement displayed on empty timeline user pages for anonymous users.
            // TRANS: %s is a user nickname. This message contains Markdown links. Keep "](" together.
            $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to them.'), $this->target->getNickname());
        }

        $this->elementStart('div', 'guide');
        $this->raw(common_markup_to_html($message));
        $this->elementEnd('div');
    }

    function showContent()
    {
        if (Event::handle('StartShowAllContent', array($this))) {
            if ($this->scoped instanceof Profile && $this->scoped->isLocal() && $this->scoped->getUser()->streamModeOnly()) {
                $nl = new PrimaryNoticeList($this->notice, $this, array('show_n'=>NOTICES_PER_PAGE));
            } else {
                $nl = new ThreadedNoticeList($this->notice, $this, $this->scoped);
            }

            $cnt = $nl->show();

            if (0 == $cnt) {
                $this->showEmptyListMessage();
            }

            $this->pagination(
                $this->page > 1, $cnt > NOTICES_PER_PAGE,
                $this->page, 'all', array('nickname' => $this->target->getNickname())
            );

            Event::handle('EndShowAllContent', array($this));
        }
    }

    function showSections()
    {
        // Show invite button, as long as site isn't closed, and
        // we have a logged in user.
        if (common_config('invite', 'enabled') && !common_config('site', 'closed') && common_logged_in()) {
            if (!common_config('site', 'private')) {
                $ibs = new InviteButtonSection(
                    $this,
                    // TRANS: Button text for inviting more users to the StatusNet instance.
                    // TRANS: Less business/enterprise-oriented language for public sites.
                    _m('BUTTON', 'Send invite')
                );
            } else {
                $ibs = new InviteButtonSection($this);
            }
            $ibs->show();
        }
    }
}

class ThreadingInboxNoticeStream extends ThreadingNoticeStream
{
    function __construct(Profile $target, Profile $scoped=null)
    {
        parent::__construct(new InboxNoticeStream($target, $scoped));
    }
}