mirror of
git://git.psyced.org/git/psyced
synced 2024-08-15 03:25:10 +00:00
791 lines
21 KiB
Text
791 lines
21 KiB
Text
// vim:noexpandtab:syntax=lpc
|
|
// $Id: place.gen,v 1.137 2008/09/12 15:37:39 lynx Exp $
|
|
//
|
|
// documentation on http://about.psyc.eu/Create_Place
|
|
//
|
|
// place.gen was inspired by loc.h, a similar room generation system in
|
|
// the Nemesis mudlib. Nemesis itself being a legendary MUD based in
|
|
// Munich (http://www.nemesis.de). the innovation in this room generation
|
|
// approach is to use the #include to generate code rather than to define
|
|
// a series of macros and hope the user uses them the right way.
|
|
// of course these days you could do a room generator in -say- perl..
|
|
// or you could implement a mega do-everything room class which can then
|
|
// be configured at runtime by web interface or slash command. in fact
|
|
// standard.c is just that, only that it didn't get all that popular.
|
|
|
|
#include <net.h>
|
|
#include <storage.h>
|
|
#include <status.h>
|
|
#include <uniform.h>
|
|
|
|
#ifndef DEFAULT_HT_LOGO
|
|
# define DEFAULT_HT_LOGO "/img/psyc.gif"
|
|
#endif
|
|
#ifndef HT_LOGO
|
|
# define HT_LOGO DEFAULT_HT_LOGO
|
|
#endif
|
|
|
|
#ifdef BRAIN
|
|
|
|
# ifdef SLAVE
|
|
# echo Configuration Error: BRAIN cannot be SLAVE
|
|
# endif
|
|
# undef CONNECT
|
|
|
|
#else
|
|
|
|
#ifndef DEFAULT_MASTER
|
|
# define DEFAULT_MASTER "psyc://psyced.org"
|
|
#endif
|
|
|
|
#ifdef CONNECT_DEFAULT
|
|
# ifdef NAME
|
|
//# if DEBUG > 0
|
|
//# echo CONNECT_DEFAULT is psyc://beta.ve.symlynX.com
|
|
//# define CONNECT "psyc://beta.ve.symlynX.com/@" NAME
|
|
//# else
|
|
|
|
// and after several changes in tagging and forking and dunnowhat
|
|
// the old master/slave system has died and not returned to life
|
|
# define REDIRECT DEFAULT_MASTER "/@" NAME
|
|
//# define CONNECT DEFAULT_MASTER "/@" NAME
|
|
//# endif
|
|
# else
|
|
# echo place.gen: Cannot use CONNECT_DEFAULT without #define NAME
|
|
# endif
|
|
#endif
|
|
|
|
#if 1
|
|
|
|
#ifdef SLAVE
|
|
//# undef SLAVE // slave system br0ken.. migrating to context slaves
|
|
// (it cannot deal with missing _tags for local joins etc etc)
|
|
# ifdef NAME
|
|
# define REDIRECT CONNECT
|
|
# ifndef CONNECT
|
|
# ifdef _uniform_node
|
|
# define CONNECT _uniform_node "@" NAME
|
|
# else
|
|
# define CONNECT "psyc://" SERVER_HOST "/@" NAME
|
|
# endif
|
|
# endif
|
|
# else
|
|
# echo place.gen: Cannot use SLAVE without #define NAME
|
|
# endif
|
|
#endif
|
|
|
|
#else
|
|
|
|
#ifdef SLAVE
|
|
# ifndef CONNECT
|
|
# ifdef NAME
|
|
# ifdef _uniform_node
|
|
# define CONNECT _uniform_node "@" NAME
|
|
# else
|
|
# define CONNECT "psyc://" SERVER_HOST "/@" NAME
|
|
# endif
|
|
# else
|
|
# echo place.gen: Cannot use SLAVE without #define NAME
|
|
# endif
|
|
# endif
|
|
#else
|
|
# ifdef CONNECT
|
|
# ifndef JUNCTION
|
|
# define SLAVE "local"
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if defined(SLAVE) || defined(VOLATILE)
|
|
# undef CONNECT_IRC
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if defined(MODERATED) && defined(PRO_PATH)
|
|
# ifdef SLAVE
|
|
inherit PRO_PATH "place/moslave";
|
|
# else
|
|
# ifdef LECTIC
|
|
inherit PRO_PATH "place/lectic";
|
|
# else
|
|
inherit PRO_PATH "place/momaster";
|
|
# endif
|
|
# endif
|
|
#else
|
|
# if defined(JUNCTION) || (defined(MASTER) && defined(SLAVE))
|
|
# define ALLOW_FROM_LINKS
|
|
inherit NET_PATH "place/junction";
|
|
# else
|
|
# ifdef SLAVE
|
|
inherit NET_PATH "place/slave";
|
|
# else
|
|
# ifdef CONNECT_IRC
|
|
# ifdef EMULATE_SERVER
|
|
inherit NET_PATH "irc/gateway";
|
|
# else
|
|
inherit NET_PATH "irc/gatebot";
|
|
# endif
|
|
# else
|
|
# ifdef THREADS
|
|
inherit NET_PATH "place/threads";
|
|
# else
|
|
# ifdef GAMESERV
|
|
inherit NET_PATH "place/gamespy";
|
|
# else
|
|
# ifdef OWNED
|
|
inherit NET_PATH "place/owned";
|
|
# else
|
|
# ifdef NEWSFEED_RSS
|
|
inherit NET_PATH "place/news";
|
|
# else
|
|
# ifdef MASTER
|
|
inherit NET_PATH "place/master";
|
|
# else
|
|
# ifdef HISTORY
|
|
inherit NET_PATH "place/storic";
|
|
# else
|
|
# ifdef MAILCAST
|
|
inherit NET_PATH "place/mailcast";
|
|
# else
|
|
# ifdef PUBLIC
|
|
inherit NET_PATH "place/public";
|
|
# else
|
|
# ifdef ON_UNKNOWN
|
|
// special place type that supports unknownmsg()
|
|
inherit NET_PATH "place/intercept";
|
|
# else
|
|
// special case in the archetype options logic, see also psyconf
|
|
# ifndef PLACE_HISTORY
|
|
# ifdef PLACE_HISTORY_EXPORT
|
|
# define PLACE_HISTORY
|
|
# endif
|
|
# endif
|
|
# include "place.i" // archetype model generator code 2007
|
|
# ifdef PLACE_HISTORY
|
|
# define HISTORY // compatibility
|
|
# endif
|
|
# ifdef PLACE_OWNED
|
|
# define OWNED PLACE_OWNED // compatibility
|
|
# endif
|
|
# endif
|
|
# endif
|
|
# endif
|
|
# endif
|
|
# endif
|
|
# endif
|
|
# endif
|
|
# endif
|
|
# endif
|
|
# endif
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef CONNECT_TELNET
|
|
inherit NET_PATH "tn/outgoing";
|
|
#endif
|
|
|
|
#ifdef FETCH_TEXTDB
|
|
volatile object feed, tob;
|
|
|
|
fetched(buffer) {
|
|
# ifdef FETCH_TEXTPATH
|
|
P1(("%O fetched: %O bytes\n", ME, strlen(buffer)))
|
|
// this destruct() should be avoidable, but there is some reason
|
|
// why it doesn't always work that needs inspection time.
|
|
if (tob) destruct(tob);
|
|
tob = (FETCH_TEXTPATH "/text") -> parseDB(buffer, FETCH_TEXTDB);
|
|
if (tob) castmsg(ME, "_notice_update_database_text",
|
|
"The text database for [_path] has been refreshed.",
|
|
([ "_path": FETCH_TEXTPATH ]) );
|
|
# else
|
|
P0(("%O fetched: %O bytes.. but what to do with it?\n",
|
|
ME, strlen(buffer)))
|
|
# endif
|
|
}
|
|
|
|
// same code in news.c !? simplify!
|
|
fetchDB() {
|
|
unless (feed) {
|
|
feed = FETCH_TEXTDB -> load();
|
|
feed->content(#'fetched, 1);
|
|
return 1;
|
|
} else {
|
|
feed->refetch(#'fetched);
|
|
return 2;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(SILENCE) || defined(NEWSFEED_RSS)
|
|
# define FILTER_PRESENCE // FILTER_TRAFFIC is also an interesting name
|
|
# define FILTER_CONVERSATION
|
|
|
|
# ifdef NEWSFEED_RSS
|
|
qNewsfeed() { return NEWSFEED_RSS; }
|
|
# define BLAME "!newsfeed"
|
|
# else
|
|
# define BLAME "!configuration"
|
|
# endif
|
|
#else
|
|
// BLAME contains an "illegal" meta-nickname indicating that something
|
|
// has been done by admin configuration rather than an interactive user
|
|
# define BLAME "!configuration"
|
|
#endif
|
|
|
|
#ifdef MAY_HISTORY
|
|
// only use this hook if PLACE_MAY_HISTORY was defined in the place
|
|
// blueprint you are using (see archetype.gen). otherwise this hook
|
|
// will have zero effect, which is the default. i don't know of any
|
|
// application who needs this. it's more like a proof of concept
|
|
// how hooks work and how they can be compile time optional.
|
|
//
|
|
mayHistory(source, mc, data, vars, b) { MAY_HISTORY; }
|
|
#endif
|
|
|
|
#ifdef HISTORY_GLIMPSE
|
|
qHistoryGlimpse() { return HISTORY_GLIMPSE; }
|
|
#endif
|
|
|
|
#ifdef OWNED
|
|
qOwners() { return ([ OWNED ]); }
|
|
|
|
# ifdef HISTORY_PROTECTION
|
|
// you have to explicitely request this behaviour as we normally
|
|
// consider it a user's privacy right to delete the history
|
|
histClear(a, b, source, mapping vars) {
|
|
if (b || qAide(SNICKER))
|
|
return ::histClear(a, b >= 50 ? b : 50, source, vars);
|
|
}
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef CHAT_CHANNEL
|
|
qChatChannel() { return CHAT_CHANNEL; }
|
|
#else
|
|
qChatChannel() { return "PSYC"; }
|
|
#endif
|
|
|
|
#if defined(RESET) || defined(CRESET) || defined(NEWSFEED_RSS) \
|
|
|| defined(RESET_INTERVAL)
|
|
void reset(int again) {
|
|
# ifdef CRESET
|
|
CRESET
|
|
# endif
|
|
# if defined(HISTORY) || defined(PLACE_HISTORY)
|
|
// basic.c currently has no reset to call
|
|
::reset(again);
|
|
# endif
|
|
# ifdef CONNECT_IRC
|
|
// if (!interactive(ME)) call_out(#'connect, 3, CONNECT_IRC);
|
|
# endif
|
|
# if __EFUN_DEFINED__(set_next_reset)
|
|
# ifdef RESET_INTERVAL
|
|
set_next_reset(RESET_INTERVAL * 60);
|
|
# else
|
|
// apparently this is needed for place/news not to
|
|
// fall into deep sleep. strange.
|
|
set_next_reset(24 * 60 * 60);
|
|
# endif
|
|
# endif
|
|
if (again) {
|
|
# ifdef RESET_INTERVAL
|
|
# if ! __EFUN_DEFINED__(set_next_reset)
|
|
if (time() < v("lastreset") + RESET_INTERVAL * 60) return;
|
|
vSet("lastreset", time());
|
|
# endif
|
|
# endif
|
|
# ifdef RESET
|
|
RESET
|
|
# endif
|
|
# ifdef NEWSFEED_RSS
|
|
connect();
|
|
# endif
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void create() {
|
|
::create();
|
|
#ifdef CRESET
|
|
CRESET
|
|
#endif
|
|
#ifdef LINK
|
|
P1(("%O - ignoring old-fashioned #define LINK %O\n", ME, LINK))
|
|
#endif
|
|
#ifdef CONNECT
|
|
# ifdef IDENTIFICATION
|
|
P1(("PLACE %O SLAVE of %O with MASTER %O\n", ME, CONNECT, IDENTIFICATION))
|
|
# else
|
|
# ifdef SLAVE
|
|
P1(("PLACE %O SLAVE of %O\n", ME, CONNECT))
|
|
# else
|
|
P1(("PLACE %O MASTER\n", ME))
|
|
# endif
|
|
# endif
|
|
# ifdef _uniform_node
|
|
# if CONNECT == _uniform_node
|
|
D1(D("link [" CONNECT "] == host ["+ _uniform_node +"]\n");)
|
|
# else
|
|
D1(D("link [" CONNECT "] != host ["+ _uniform_node +"]\n");)
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
#if 0 //def CONNECT
|
|
P0(("..\nPLACE %O initiating connection to %O\n", ME, CONNECT))
|
|
clone_object(PSYC_PATH "active") -> connect(CONNECT);
|
|
#endif
|
|
#ifdef NAME
|
|
// double load happens only with certain room types
|
|
// this load() is important to set identification var
|
|
// replacing it is no solution
|
|
//sName(NAME); vSet("name", NAME);
|
|
load(NAME, 1);
|
|
#else
|
|
load();
|
|
#endif
|
|
|
|
#if defined(FILTER_PRESENCE) || defined(QUIET)
|
|
vSet("_filter_presence", BLAME);
|
|
#endif
|
|
#if defined(FILTER_CONVERSATION) || defined(SILENT)
|
|
vSet("_filter_conversation", BLAME);
|
|
#endif
|
|
#ifdef RESTRICTED
|
|
vSet("_restrict_invitation", BLAME);
|
|
#else
|
|
vDel("_restrict_invitation");
|
|
#endif
|
|
#ifdef UNIFORM_STYLE
|
|
vSet("_uniform_style", UNIFORM_STYLE);
|
|
#endif
|
|
//#ifdef IRCGATE_NAME
|
|
// vSet("_gateway_name", IRCGATE_NAME);
|
|
//#endif
|
|
|
|
#ifdef SLAVE
|
|
# ifdef CONNECT
|
|
// this needs to happen before sIdentification
|
|
sMaster(CONNECT);
|
|
# endif
|
|
# if defined(IDENTIFICATION)
|
|
sIdentification(IDENTIFICATION);
|
|
# endif
|
|
#endif
|
|
#ifdef CONNECT_IRC
|
|
link(CONNECT_IRC);
|
|
#endif
|
|
#ifdef CONNECT_TELNET
|
|
link(CONNECT_TELNET);
|
|
#endif
|
|
#if defined(NEWSFEED_RSS) && defined(DEVELOPMENT)
|
|
// do not connect newsfeeds immediately if running in production mode
|
|
connect();
|
|
#endif
|
|
#ifdef MODERATED
|
|
# define ALLOW_EXTERNAL // FROM_LINKS?
|
|
# ifdef PRO_PATH
|
|
sModeratable(1);
|
|
# endif
|
|
#endif
|
|
// exits currently not supported
|
|
#ifdef EXITS
|
|
// sExits( EXITS );
|
|
#endif
|
|
#ifdef CREATE
|
|
CREATE
|
|
#endif
|
|
}
|
|
|
|
#ifdef PRIVATE
|
|
//qPublic() { return 0; }
|
|
#else
|
|
qPublicName() { return MYNICK; }
|
|
qPublic() { return BLAME; }
|
|
#endif
|
|
|
|
#ifdef ALLOW_EXTERNAL
|
|
qAllowExternal() { return 1; }
|
|
#else
|
|
# if defined(ALLOW_EXTERNAL_FROM) || defined(ALLOW_FROM_LINKS) \
|
|
|| defined(ALLOW_EXTERNAL_HOST) || defined(ALLOW_METHOD) \
|
|
|| defined(ALLOW_EXTERNAL_LOCALS) || defined(ALLOW_TRUSTED)
|
|
qAllowExternal(source, mc, vars) {
|
|
P2(("qAllowExternal(%O,%O,%O)\n", source,mc,vars))
|
|
// only one #define of ALLOW_* type makes sense
|
|
// unless (abbrev("_notice_news", mc)) return 0;
|
|
// unless (abbrev("_notice_software", mc)) return 0;
|
|
# ifdef ALLOW_TRUSTED
|
|
if (vars["_INTERNAL_trust"] > 5) return 1;
|
|
# endif
|
|
# ifdef ALLOW_METHOD
|
|
unless (abbrev(ALLOW_METHOD, mc)) return 0;
|
|
# endif
|
|
if (stringp(source)) {
|
|
# ifdef ALLOW_FROM_LINKS
|
|
// does this make things spoofable?
|
|
if (isLink(source) || isLink(vars["_source_relay"])) return 1;
|
|
# endif
|
|
# ifdef ALLOW_EXTERNAL_FROM
|
|
if (abbrev(ALLOW_EXTERNAL_FROM, source)) return 1;
|
|
# endif
|
|
# ifdef ALLOW_EXTERNAL_HOST
|
|
string *u = parse_uniform(source);
|
|
if (u && same_host(ALLOW_EXTERNAL_HOST, u[UHost])) return 1;
|
|
# endif
|
|
return 0;
|
|
}
|
|
# ifdef ALLOW_EXTERNAL_HOST
|
|
// does anyone need this?
|
|
//else if (same_host(ALLOW_EXTERNAL_HOST, query_ip_number(source))) return 1;
|
|
# endif
|
|
# ifdef ALLOW_EXTERNAL_LOCALS
|
|
// this is equivalent to irc/mode -n for local ircers. thx fip.
|
|
return 1;
|
|
# else
|
|
return 0;
|
|
# endif
|
|
}
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef LAYOUT
|
|
viewHead() { return LAYOUT; }
|
|
#endif
|
|
|
|
#if defined(REQUEST_ENTER) || defined(REGISTERED) || defined(SECURE) ||\
|
|
defined(RESTRICTED) || defined(TRUSTED) || defined(NICKLESS) ||\
|
|
defined(LOCAL)
|
|
volatile mixed lastTry;
|
|
|
|
# if defined(SECURE) && defined(HISTORY) && defined(PLACE_HISTORY_EXPORT)
|
|
# undef PLACE_HISTORY_EXPORT
|
|
# endif
|
|
|
|
enter(source, mc, data, vars) {
|
|
# ifdef TRUSTED
|
|
if (vars["_INTERNAL_trust"] > 5) return 1;
|
|
# endif
|
|
# ifdef LOCAL
|
|
unless (objectp(source)) {
|
|
sendmsg(source, "_error_place_enter_restricted_local",
|
|
"Sorry, [_nick_place] is only accessible for users of the same server.",
|
|
([ "_nick_place" : MYNICK ]) );
|
|
if (source != lastTry) {
|
|
vars["_source_relay"] = source;
|
|
castmsg(ME, "_failure_place_enter_restricted_local",
|
|
"Admission into [_nick_place] denied for remote user [_source_relay].",
|
|
vars);
|
|
lastTry = source;
|
|
}
|
|
return 0;
|
|
}
|
|
# endif
|
|
# ifdef RESTRICTED
|
|
unless (qAide(SNICKER)) {
|
|
sendmsg(source, "_error_place_enter_necessary_invitation",
|
|
"[_nick_place] can only be entered upon invitation.",
|
|
([ "_nick_place" : qName() ]) );
|
|
if (source != lastTry) {
|
|
castmsg(ME, "_failure_place_enter_necessary_invitation",
|
|
"Admission into [_nick_place] denied for uninvited user [_nick].",
|
|
vars);
|
|
lastTry = source;
|
|
}
|
|
return 0;
|
|
}
|
|
# endif
|
|
# if defined(SECURE)
|
|
// let people in who are either connected via an MITM-prone TLS
|
|
// protocol or are coming from the reasonably safe localhost
|
|
// (either SSH or Tor 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
|
|
//
|
|
// SECURE by itself also doesn't enforce that people are registered
|
|
// or belong to a certain group, so you have to use the respective
|
|
// #defines to also ensure that, if that's what you want.
|
|
//
|
|
// -lynX 2004, updated 2015
|
|
//
|
|
int intimacy = probably_private(source);
|
|
// psyc client.. may also one day be a psyc server, in that
|
|
// case we have to hope the rest of the link is secured, too
|
|
if (intimacy == PRIVACY_UNKNOWN)
|
|
intimacy = probably_private(vars["_INTERNAL_origin"]);
|
|
if (intimacy <= PRIVACY_SURVEILLED) {
|
|
sendmsg(source, "_error_place_enter_necessary_encryption",
|
|
"[_nick_place] may only be accessed by clients with enabled encryption.",
|
|
([ "_nick_place" : qName() ]) );
|
|
if (source != lastTry) {
|
|
castmsg(ME, "_failure_place_enter_necessary_encryption",
|
|
"Admission into [_nick_place] denied for insecure user [_nick].",
|
|
vars);
|
|
lastTry = source;
|
|
}
|
|
return 0;
|
|
}
|
|
# endif
|
|
# if defined(REGISTERED)
|
|
if (objectp(source) && source->isNewbie()) {
|
|
sendmsg(source, "_error_place_enter_necessary_registration",
|
|
"We want you to be a registered PSYC user before entering [_nick_place].",
|
|
([ "_nick_place" : MYNICK ]) );
|
|
if (source != lastTry) {
|
|
castmsg(ME, "_failure_place_enter_necessary_registration",
|
|
"Admission into [_nick_place] denied for unregistered user \"[_nick]\".",
|
|
vars);
|
|
lastTry = source;
|
|
}
|
|
return 0;
|
|
}
|
|
# endif
|
|
# if defined(REQUEST_ENTER)
|
|
REQUEST_ENTER
|
|
# endif
|
|
# ifdef NICKLESS
|
|
return 1; // LEGAL_NICK_IN_ENTER
|
|
# else
|
|
return ::enter(source, mc, data, vars);
|
|
# endif
|
|
}
|
|
#endif
|
|
|
|
#if defined(ON_STATUS)
|
|
showStatus(verbosity, al, source, mc, data, vars) {
|
|
ON_STATUS
|
|
return ::showStatus(verbosity, al, source, mc, data, vars);
|
|
}
|
|
#endif
|
|
|
|
#if defined(ON_ANY) || defined(ON_CONVERSE) || defined(REDIRECT)
|
|
msg(source, mc, data, vars) {
|
|
# ifdef ON_ANY
|
|
ON_ANY
|
|
# endif
|
|
# ifdef ON_CONVERSE
|
|
if (abbrev("_message", mc)) {
|
|
ON_CONVERSE
|
|
}
|
|
# endif
|
|
# ifdef REDIRECT
|
|
sendmsg(source, "_failure_redirect_temporary",
|
|
"[_nick_place] is currently unable to fulfil this operation. Please direct your request to [_source_redirect]",
|
|
([ "_method_relay": mc,
|
|
"_tag_reply" : vars["_tag"] || 0,
|
|
// "_data_relay" : data,
|
|
# ifdef NAME
|
|
"_nick_place" : NAME,
|
|
# else
|
|
"_nick_place" : MYNICK,
|
|
# endif
|
|
"_source_redirect": REDIRECT ]));
|
|
return 0;
|
|
# else
|
|
::msg(source, mc, data, vars);
|
|
# endif
|
|
}
|
|
#endif
|
|
|
|
// this hook only works in archetypes that support it
|
|
#ifdef ON_UNKNOWN
|
|
unknownmsg(source, mc, data, vars) {
|
|
ON_UNKNOWN
|
|
::unknownmsg(source, mc, data, vars);
|
|
}
|
|
#endif
|
|
|
|
#ifdef ON_ENTER
|
|
onEnter(source, mc, data, vars) {
|
|
ON_ENTER
|
|
return ::onEnter(source, mc, data, vars);
|
|
}
|
|
#endif
|
|
|
|
// obsolete for new code.. use PLACE_HISTORY_EXPORT or not
|
|
#ifdef HISTORY_PRIVATE
|
|
# echo HISTORY_PRIVATE is obsolete. Unset PLACE_HISTORY_EXPORT instead.
|
|
// disables web-export of HISTORY in a somewhat drastic way, i admit
|
|
htget(prot, query, headers, qs) {
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CHALLENGE_QUESTION // should make media player etc work also w/o challenge FIXME
|
|
#include <sys/regexp.h>
|
|
#include "ht/http.h"
|
|
|
|
#define CHALOG(verb) log_file("CHALLENGE", "%s %s %O A:%O P:%O C:%O\n", \
|
|
MYNICK, verb, query_ip_name(), \
|
|
query["answer"], query["parameters"], headers["cookie"])
|
|
|
|
// maybe this all belongs into archetype.gen.. chesmo!
|
|
htget(prot, query, headers, qs, data, noprocess) {
|
|
PT(("%O place.gen::htget\n", ME))
|
|
if (probably_private(this_interactive()) <= PRIVACY_SURVEILLED) {
|
|
hterror(prot, R_PAYMENTREQ, "To protect against abuse in this nasty world this function needs 'https' instead of 'http'.");
|
|
htnotify(query, headers, "_challenge_disabled_encryption",
|
|
"[_nick_place] sees no TLS by [_web_on] from [_web_from].");
|
|
return 0;
|
|
}
|
|
string item = "/@"+ MYNICK;
|
|
if (
|
|
# ifdef CHALLENGE_AGENT
|
|
stringp(headers["user-agent"]) &&
|
|
regmatch(lower_case(headers["user-agent"]), CHALLENGE_AGENT)
|
|
# else
|
|
# ifdef CHALLENGE_ACCOUNTS
|
|
# define CHALLENGE_CHECK CHALLENGE_ACCOUNTS
|
|
# else
|
|
# ifdef CHALLENGE_MATCH
|
|
# define CHALLENGE_CHECK CHALLENGE_MATCH
|
|
# endif
|
|
# endif
|
|
stringp(headers["cookie"]) && regmatch(headers["cookie"],
|
|
"challenge=complete&answer="+ md5(CHALLENGE_CHECK))
|
|
# endif
|
|
) {
|
|
CHALOG("completes");
|
|
htnotify(query, headers, "_challenge_accomplished_web",
|
|
"Challenge accomplished in [_nick_place] by [_web_on] coming from [_web_from].");
|
|
# ifdef CHALLENGE_REDIRECT
|
|
sTextPath(query["layout"], query["lang"], "html");
|
|
# ifdef CHALLENGE_REDIRECT_TITLE
|
|
# ifdef CHALLENGE_QUESTION
|
|
htok3(prot, 0, "Set-Cookie: psycplace=\"challenge=done\"; Path="+ item +"; Secure; Max-Age=9\n");
|
|
# else
|
|
htok();
|
|
# endif
|
|
// you can output a player iframe instead of a redirect...
|
|
w("_PAGES_frame_redirect", 0,
|
|
([ "_uniform_page" : CHALLENGE_REDIRECT,
|
|
"_title_page" : CHALLENGE_REDIRECT_TITLE,
|
|
"_nick_place" : MYNICK ]) );
|
|
return 1;
|
|
# else
|
|
return htredirect(prot, CHALLENGE_REDIRECT, "Download or redirect initiated", 0, "Content-Disposition: attachment\nSet-Cookie: psycplace=\"challenge=done\"; Path="+ item +"; Secure; Max-Age=9\n");
|
|
# endif
|
|
# else
|
|
# ifdef HTGET
|
|
return HTGET;
|
|
# else
|
|
return ::htget(prot, query, headers, qs, data, noprocess);
|
|
# endif
|
|
# endif
|
|
}
|
|
# if defined(CHALLENGE_MATCH) || defined(CHALLENGE_ACCOUNTS)
|
|
if (stringp(query["answer"])) {
|
|
unless (headers["cookie"]) {
|
|
CHALOG("disabled");
|
|
hterror(prot, R_PAYMENTREQ, "To protect against abuse in this nasty world this function needs just temporarily enabled cookies. There are no de-anonymizing purposes involved. Or did you just lowercase my name in the URL?");
|
|
htnotify(query, headers, "_challenge_disabled_web",
|
|
"[_nick_place] sees no cookies by [_web_on] from [_web_from].");
|
|
return 1;
|
|
}
|
|
string acct;
|
|
if (regmatch(headers["cookie"], "challenge=given")) {
|
|
if (query["answer"] &&
|
|
# ifdef CHALLENGE_ACCOUNTS
|
|
(acct = CHALLENGE_ACCOUNTS->consult(query["answer"]))
|
|
# else
|
|
regmatch(lower_case(query["answer"]), CHALLENGE_MATCH)
|
|
# endif
|
|
) {
|
|
// lazy me could have used referer here ;)
|
|
string nu = stringp(query["parameters"]) &&
|
|
strlen(query["parameters"]) &&
|
|
query["parameters"] != "0" ?
|
|
item +"?"+ query["parameters"] : item;
|
|
CHALOG(acct? ("authenticates as "+ acct): "reloads");
|
|
htredirect(prot, nu, "Reload, please", 0, "Set-Cookie: psycplace=\"challenge=complete&answer="+ md5(CHALLENGE_CHECK) +"\"; Path="+ item +"; Secure; Max-Age=99\n");
|
|
if (acct) htnotify(query, headers, "_challenge_authenticated_web",
|
|
"[_web_on] authenticated for [_nick_place] coming from [_web_from].", acct);
|
|
return 1;
|
|
} else {
|
|
CHALOG("fails");
|
|
htnotify(query, headers, "_challenge_failed_web",
|
|
"[_nick_place] sees [_web_on] from [_web_from] fail the challenge.");
|
|
}
|
|
}
|
|
} else
|
|
# endif
|
|
{
|
|
CHALOG("challenges");
|
|
htnotify(query, headers, "_challenge_presented_web",
|
|
"[_nick_place] challenges [_web_on] coming from [_web_from].");
|
|
// (query [_web_query], cookie [_web_cookie]).");
|
|
}
|
|
// If you have trouble reloading the HTML template
|
|
// look out for both 'ht' and 'html' textdbs!
|
|
sTextPath(query["layout"], query["lang"], "html");
|
|
// using a non-psyced cookie here so that you can't construct a
|
|
// url that allows other people to bypass the challenge.
|
|
htok3(prot, 0, "Set-Cookie: psycplace=\"challenge=given\"; Path="+ item +"; Secure; Max-Age=999\n");
|
|
# ifndef CHALLENGE_REDIRECT_TITLE
|
|
# define CHALLENGE_REDIRECT_TITLE "Challenge for "+ MYNICK
|
|
# endif
|
|
w("_PAGES_group_challenge", 0,
|
|
([ "_challenge" : htquote(CHALLENGE_QUESTION),
|
|
// if the user failed the challenge,
|
|
// we maintain the original qs for next attempt:
|
|
"_parameters" : query["parameters"] || qs,
|
|
"_uniform_logo" : HT_LOGO,
|
|
"_title_page" : CHALLENGE_REDIRECT_TITLE,
|
|
"_nick_place" : MYNICK ]) );
|
|
// printf("%O vs %O\n", query, headers);
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
#ifdef HISTORY
|
|
# if defined(HISTORY_METHOD) || defined(HISTORY_MAY_LOG)
|
|
mayLog(mc) {
|
|
# ifdef HISTORY_MAY_LOG
|
|
HISTORY_MAY_LOG
|
|
# endif
|
|
# ifdef HISTORY_METHOD
|
|
return abbrev(HISTORY_METHOD, mc);
|
|
# endif
|
|
}
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef ON_ERROR
|
|
error(source, mc, data, vars) {
|
|
ON_ERROR
|
|
}
|
|
#endif
|
|
|
|
#ifdef ON_COMMAND
|
|
cmd(command, args, privilege, source, vars) {
|
|
ON_COMMAND
|
|
return ::cmd(command, args, privilege, source, vars);
|
|
}
|
|
#endif
|
|
|
|
#if defined(PASS_IRC) || defined(ON_CONNECT)
|
|
logon(failure) {
|
|
int rc = ::logon(failure);
|
|
unless (rc) return 0;
|
|
# ifdef PASS_IRC
|
|
emit("PASS :"+ PASS_IRC +"\r\n");
|
|
# endif
|
|
# ifdef ON_CONNECT
|
|
ON_CONNECT
|
|
# endif
|
|
return rc;
|
|
}
|
|
#endif
|
|
|
|
#ifdef NEWS_PUBLISH
|
|
publish(link, headline, channel) {
|
|
unless (NEWS_PUBLISH(link, headline, channel))
|
|
::publish(link, headline, channel);
|
|
}
|
|
#endif
|