Conference control is to a large extent implemented by programmable context masters and in particular places.

Contents

Set up a Place Manager without psyced

We don't have any finished implementation for place managers other than psyced, but we have a couple of software projects which give you a framework. It should be feasible to make an independent room server in a perlpsyc script for instance. Just imagine, you can run your own independent chatroom in a bunch of lines of perl. But for now it is much more comfortable to implement your requirements within the elaborate framework of psyced, even if you may have to get used to a little bit of LPC. It's not hard, actually it's easier than perl. And if you're sticking to just the functions provided by the User Directives listed below, you don't need to write a single line of LPC.

Using psyced: Ad-hoc Standard Rooms

To create a standard room all you have to do is make up the name or PSYC address for it and /enter it. psyced will allocate it for you, unless this has explicitely been disabled by your psyced administrator. Once created, typical room commands are available, like for example to turn a private room into a public one. These are documented in the psyced Manual.

Using psyced: Custom Rooms

In PSYC, groups, rooms, places, they are like little programs which run within the framework of the server. In the case of psyced, these rooms are kept in the "place" subdirectory at the top level, so that you can easily access them. You will find several example and standard rooms in there. To create a new room simply copy a file and edit it to your wishes.

You could write such a room completely from scratch, but most likely you will want to plug together a room to your needs, then you can still tweak it with direct LPC programming. But you don't have to.

We have created a preprocessor-based room generator called place.gen. With a couple of #define's in front of the #include you have created your custom room program. Understand that this include file operates in a way completely opposite to how #include is normally employed, and that's why it needs to come after all the #define's, not in front of them!

Consider that your room's filename must be in lower case, but using the #define NAME you can change the way it then appears in PSYC.

Also useful to know: psyced tries to compile your new place the first time you enter it, but you can also intentionally load it using the /reload place/<placenick> command. Reload takes an LPC object path as argument (which is the same as the path starting at the world sandbox without the trailing .c), not a nickname or uniform. Should the place fail to compile, the console log will give you LPC-specific error information. This command is only available to operators and administrators.

As if that wasn't enough, psyced also provides an API for spawning external programs.

User Directives

#define ALLOW_EXTERNAL

This allows any external PSYC entity to submit messages to this room for rebroadcast. Careful! You probably want to limit this by using any or several of the following:

#define ALLOW_EXTERNAL_LOCALS

Allow local objects on the same server to send messages hereto. Currently this only works for local IRC client users who can send to a channel they haven't effectively joined.

#define ALLOW_EXTERNAL_FROM <uniform>

Only allow sources whose uniform starts with the above.

#define ALLOW_EXTERNAL_HOST <host>

Only allow sources from a certain host. You can specify either a hostname or IP address. This is slightly more calculation intensive than comparing a uniform.

#define ALLOW_FROM_LINKS

Allow places that have linked this place (like junctions) to submit messages.

#define ALLOW_METHOD <methodfamily>

Only allow methods that abbreviate to the given method family, like "_notice_news".

#define ALLOW_TRUSTED

External messages coming from a trusted connection are welcome.

#define CONNECT <uniform>

The room is a slave or junction of a master it is supposed to link to.

#define CONNECT_IRC <ircserver>

The room is a gateway to an IRC network. You shall specify the <ircserver> as a string. If you need to specify a port number, you can do:

#define CONNECT_IRC "irc.example.net", 6669

The architecture of IRC network gatebots is however bound to be changed someday.

#define CHAT_CHANNEL <namewithoutdash>

Which channel should the gateway link to. It normally enters #PSYC on the remote IRC network. You need to specify "spacks" if you want it to join #spacks. Non-dash IRC-channels are currently not supported as the IRC networks are totally inconsistent on their availability (I would've preferred +PSYC over #PSYC). This #define deserves to be renamed into CHANNEL_IRC or LINK_IRC, but then again once the IRC gateway system is rewritten to support multiple channels we will hopefully be able to use #define CONNECT with IRC uniforms. So for now, let's just leave it as it is.

#define PASS_IRC <password>

A password to authenticate yourself with the IRC server, if needed.

#define FILTER_CONVERSATION

This room is not for talking.

#define FILTER_PRESENCE

Doesn't distribute enter/leave notices from users.

#define GAMESERV

A place that has the ability to communicate with a game spy server.

#define IDENTIFICATION <uniform>

Specify the UNI of this room, if it isn't just psyc://serverhost/@name. You can use this for virtual hosting, using alternate domain names of your server host. It is also used in conjunction with junctions, but you will use #define CONNECT in that case.

#define LOCAL

This will require all people entering to be local to the server hosting the place, not remote coming via an interserver protocol.

#define MAILCAST

Mailcast is a room with a special secondary history of received SMTP messages using the *room@host e-mail syntax.

#define NAME <propercasedstring>

A place is always named after its filename, so this #define only serves the purpose to change the case if you don't like the default first-character-uppercased style, as in #define NAME "CrAzYrOOm".

#define NEWSFEED_RSS <RSS-URL>

Real PSYC newsfeeds need to set up some ALLOW_EXTERNAL. This is only for RSS-based (legacy support) newsfeeds. This room implements an RSS polling station which will periodically tamper a webserver on changes on a file which hopefully is according to some more or less decent version of the RSS file format. See also RESET_INTERVAL.

Yes, we don't encourage using RSS, tell your news provider to generate notifications directly in PSYC, see Wikinotify for an example how to do that. It's hugely simpler and better as you can see.

#define PLACE_HISTORY

This room implements log keeping of conversation in a history.

#define HISTORY_GLIMPSE <amount>

Specify how many "lines" of history are sent to a newly entering member, if you don't like the system default.

#define HISTORY_METHOD <methodfamily>

Specify the method family which is to be kept in the log. Normally this is the case for conversational messages.

#define HISTORY_PROTECTION

In OWNED places this disallows the regular inhabitant to delete or reduce the size of the history. This is only appropriate for places where casual conversations will never happen, like in large announcement channels.

#define PLACE_HISTORY_EXPORT

This enables web export of chat history, implies PLACE_HISTORY.

#define PLACE_MASQUERADE

You can play with your nicknames in this place, see Masquerade.

#define PLACE_OWNED <list>

where <list> is a series of strings containing lowercased uniforms or local nicknames, like in this example:

#define PLACE_OWNED "billyidol", "nikkershaw", "psyc://neuromantic.jp/~yukihirotakahashi"

Owned rooms have very specific characteristics which should be explained in the psyced Manual.

#define PLACE_SCRATCHPAD

This place provides a scratchpad tool on its web homepage.

#define RESTRICTED

Only allow owners and aides to enter the room. No strangers accepted. In this configuration the /invite command also raises that person to aide status, so this is effectively what it needs for an invite-only room. An /uninvite command is also provided, but it's just equivalent to /unmandate. Neither does it inform the person, nor does it kick anyone out if already in.

#define PRIVATE

Don't list this room in any form of public listing like the server's local /people list.

#define REDIRECT <uniform>

Disable this room and redirect all visitors to a different address.

#define REGISTERED

Only allow people in who have an identification, that is - they have registered with their server and set up a password or other form of authentication.

#define RESET_INTERVAL <minutes>

Resets are an LPC concept from the MUD days. Objects can register for periodic reset calls to do periodic jobs. This will change the default amount of minutes between resets. A NEWSFEED_RSS room uses resets to periodically poll for changes in the monitored remote file. You can change how often by defining RESET_INTERVAL.

#define SECURE

This room lets people in, who are either connected via a SSL/TLS protocol or are coming from the localhost (probably SSH users). Both cases are no absolute guarantee for safety.. it is still in the hands of each user in the room to safeguard true secrecy.

#define THREADS

This room comes with a threaded forum or blog feature. See threads for more.

#define TRUSTED

People coming from a trusted connection may enter.

#define UNIFORM_STYLE <location>

Specify the CSS style sheet that should be used when displaying content of this place in a style sheet capable display. The <location> must be an HTTP URL.

Examples

Simple Example

// this room lets people in who are either connected via a SSL/TLS
// protocol or are coming from the localhost (probably SSH users).
//
// both cases are no absolute guarantee for safety.. it is still
// in the hands of each user in the room to safeguard true secrecy
//
// -lynX 2004

#define SECURE
#include <place.gen>

Example of a blog room

#define NAME "blog"
#define THREADS
#define HISTORY  
#define HISTORY_GLIMPSE 12
#include <place.gen>

Example with custom logic

#define NAME "TELEX"
#define HISTORY 
#define ON_ANY telexify(&data, &vars);
#include <place.gen>

/*** 6-BIT ROOM FOR 60S/70S COMPUTER *** ONLY SUPPORTS UPPER CASE TEXT ***/

mapping cache = ([ "lynX" : "lynX" ]);

telexify(data, vars) {
        string k, val;

        foreach (k, val: vars) if (stringp(val)) { 
                if (cache[val]) vars[k] = cache[val];
                else vars[k] = cache[val] = upper_case(val);
        }
        if (stringp(data)) {
                data = upper_case(data);
        }
}

Update: The cache is actually a stupid idea because the upper_case() efun actually performs faster than looking up a string in a mapping.

Developer Directives

These directives are only useful to Developers who are planning to add custom code to the room. If you find this interesting and would learn how to do these things, please read our introduction to LPC.

Creation and Reset

#define CREATE <code>

This is a piece of LPC code which will be executed once when the room is instantiated.

#define RESET <code>

If you need a piece of LPC code to be executed every so-and-so minutes, you can pass it in using RESET. See also RESET_INTERVAL.

#define CRESET <code>

Here goes your code which is intended to run both at creation time and periodically at every reset.

#define HISTORY_MAY_LOG <code>

return 1 for any method that is allowed to be kept in a log. The (mc) variable is available to you here.

#define ON_ANY <code>

Execute this code for every incoming message (all kinds). The typical variables (source, mc, data, vars) are available for you to peruse.

#define ON_COMMAND <code>

Implement parsing for extra commands. This is very specific to the current implementation of command parsing in psyced and therefore liable to change. The variables (source, command, args, privilege) are available to you here. source is the executing user. command contains the lowercased command without command characters, like "slap". args contains an array of things the user has given us. privilege is set if the user is an administrator of your server. return 1 if your command parsing was successful.

#define ON_CONNECT <code>

Something to do when a TCP connection has successfully been established on this object. Typically used in Gatebots to submit extra commands to an IRC server.

#define ON_CONVERSE <code>

Execute this code for incoming conversational messages only. The typical variables (source, mc, data, vars) are available for you to peruse.

#define REQUEST_ENTER <code>

return 0 if you don't want a person to enter the room. The typical variables (source, mc, data, vars) are available for you to peruse. Don't use this for greeting messages. See ON_ENTER.

#define ON_ENTER <code>

Use this instead of REQUEST_ENTER when you want something to take place just after a person has entered the place, like sending a special greeting message. The typical variables (source, mc, data, vars) are available for you to peruse. You can return 0 if you want to suppress the regular greeting status messages, otherwise ON_STATUS will also be triggered. See below.

#define ON_ERROR <code>

Run this code when an _error _failure or _warning is transmitted to the room. The typical variables (source, mc, data, vars) are available for you to peruse.

#define ON_STATUS <code>

Run this code when a status output is to be sent to a person. This happens when she enters the place, or when she asks for it manually (using /s or /st commands etc). This lets you add extra status items or behaviour. A status output should never modify data, it only shows current state of things. The typical variables (source, mc, data, vars) are available, were source is the person asking. Additionally verbosity is defined according to status.h. A typical statement could look like this:

#define ON_STATUS if (verbosity & VERBOSITY_MEDIUM) \
    sendmsg(source, "_status_place_mood", \
       "The chatroom has a [_degree_mood] mood today", \
        ([ "_degree_mood", v("mood") ]));

Of course you'd also need an ON_COMMAND to set the mood, according to this example.

#define ON_UNKNOWN <code>

only gets called when messages have passed the regular message handler, didn't encounter any other kind of handling and would normally be multicast next. Typically happens with external messages coming via an ALLOW_* macro (see above). The usual (source, mc, data, vars) are available. If you "return;", the multicast will not be executed.

Currently this macro is implemented in a way that it automatically enables PLACE_HISTORY and PLACE_OWNED and disables PLACE_MASQUERADE and PLACE_SCRATCHPAD. If that's a problem, let us know.

#define NEWS_PUBLISH(link, headline, channel) <expression>

You can use this macro to define your own way how to castmsg() the reception of news in an extra function, or to filter the news by making an expression that returns true. If the result of this macro is false, then the normal castmsg() call for news will run. So this may either be useful when you need a custom mc for this type of news, but also when some quirk in the RSS file requires you to throw away some special cases. The arguments passed are the URL, the title or news headline for this URL and the general title for this newscast.

Special Purpose Directives

Remote TextDB

This is something very technical you will hardly ever feel the need to use. In fact it hardly has anything to do with places.

It is generally a better idea to have textdb files available locally. In particular, there is a time gap as the fetch is operating, where the textdb is in an undefined state.

Should you need this anyway, this is what you have to do:

#define FETCH_TEXTDB <URL>

Define an http URL where a .textdb file is stored.

Additionally you need a method to trigger the operation of fetching the textdb, by use of an admin command maybe:

#define ON_COMMAND if (privilege && command == "fetch")\
                            { return fetchDB(); }

or simply at creation time:

#define ON_CREATE fetchDB();

You also need to

#define FETCH_TEXTPATH <textpath>

define which textdb is to be overwritten by this fetch operation. This would be a path like "default/es/plain" for a spanish translation of the default plain text database.

Message flow in psyced places

How can you make your room do just what you want, make the best use of all the useful code in the psyced place generators and still potentially tweak nearly everything about how it is being done. This is never architecturally easy. Here's an explanation how it is being done. You can also skip this and go straight to the conclusion.

  1. Messages are either native PSYC or commands relayed by the identity.
  2. They arrive into the place using the msg() or cmd() APIs respectively.
  3. Special places overload these methods for extended functionality, but it is generally not recommended. There are finer grained possibilities.
  4. msg and cmd either try to figure out things themselves (old style) or they employ the signature mechanism (new style) which handles both techniques and calls appropriate message handlers using a unified interface with PSYC variables.
  5. The message handlers are typically called
    _request_something(source, mc, data, vars, more)
    where more are the arguments given at the call_signature() call.
  6. When you need to extend the behaviour of such a handler, you can overload it, then attach your behaviour before (also known as prefilter in ppp) or after (postfilter) the ::handler() inheritance call.
  7. In some cases the handler already has some kind of before or after or even in between behaviour that you would like to mess with or simply disable (for example _request_history is usually only available to place members, but you may want to remove this restriction). In this case the handlers in the place blueprints provide hook functions that you can overload and modify.

Since all of this is confusing, especially knowing when you should overload an entire handler or just one of its hooks, we try to provide every imaginable plug-in point as a #define macro in place.gen, which then knows which path to take (and may even be changed as the archetype.gen system evolves). So it is better not to use these hooks directly, as some of the older place examples do. Should a semantic hook in form of such a #define be missing and not covering your needs, it's probably best to modify the system to add it in, rather than working out some ways to circumvent it.