2009-01-26 19:21:29 +00:00
|
|
|
|
// vim:foldmethod=marker:syntax=lpc
|
2009-01-26 20:12:53 +00:00
|
|
|
|
// $Id: entity.c,v 1.127 2008/08/05 12:24:16 lynx Exp $
|
2009-01-26 19:21:29 +00:00
|
|
|
|
//
|
|
|
|
|
// entity.c: anything that has a UNI (see http://about.psyc.eu/uniform)
|
|
|
|
|
// this file handles some low-level issues with being an entity:
|
|
|
|
|
//
|
|
|
|
|
// * resolve UNLs and UNRs into UNIs and back, so higher level
|
|
|
|
|
// processing knows who they are dealing with, no matter which
|
|
|
|
|
// agent operated on this person's behalf
|
|
|
|
|
// * state: handle the inter-entity MMP state variables, packet
|
|
|
|
|
// ids and message history
|
|
|
|
|
// * trust network: figure out who we trust and who we can ask to find
|
|
|
|
|
// out if someone is trustworthy etc etc
|
|
|
|
|
|
2009-01-26 20:12:53 +00:00
|
|
|
|
// local debug messages - turn them on by using psyclpc -DDentity=<level>
|
|
|
|
|
#ifdef Dentity
|
|
|
|
|
# undef DEBUG
|
|
|
|
|
# define DEBUG Dentity
|
|
|
|
|
#endif
|
|
|
|
|
|
2009-01-26 19:21:29 +00:00
|
|
|
|
#include <net.h>
|
|
|
|
|
#include <storage.h>
|
2009-03-03 23:40:26 +00:00
|
|
|
|
#include <uniform.h>
|
2009-01-26 19:21:29 +00:00
|
|
|
|
|
|
|
|
|
#ifdef ENTITY_STATE //{{{
|
|
|
|
|
# define HEADER_ONLY
|
|
|
|
|
# include "state.c"
|
|
|
|
|
# undef HEADER_ONLY
|
|
|
|
|
#endif //}}}
|
|
|
|
|
|
|
|
|
|
#ifndef MINIMUM_TRUST
|
|
|
|
|
# define MINIMUM_TRUST 5
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef MAXIMUM_TRUST
|
|
|
|
|
# define MAXIMUM_TRUST 10
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef NEW_QUEUE
|
|
|
|
|
inherit NET_PATH "queue2";
|
|
|
|
|
#else
|
|
|
|
|
inherit NET_PATH "queue";
|
|
|
|
|
#endif
|
|
|
|
|
inherit NET_PATH "name";
|
|
|
|
|
inherit NET_PATH "storage";
|
|
|
|
|
#ifdef ENTITY_STATE //{{{
|
|
|
|
|
volatile mapping _state, _ostate, _cstate, _icount, _count, _memory;
|
|
|
|
|
volatile mapping temp, unused;
|
|
|
|
|
#endif //}}}
|
|
|
|
|
|
|
|
|
|
// this ifdef disables uni2unl, yet it doesn't remove all the queuing
|
|
|
|
|
// and async auth requests. should it?
|
|
|
|
|
#ifdef UNL_ROUTING //{{{
|
|
|
|
|
// while unl2uni in psyc/library is currently only used for local users'
|
|
|
|
|
// clients (and by FORK code, which in exchange doesn't use this code here)
|
|
|
|
|
// this is the place where general UNI to UNL mapping is made.
|
|
|
|
|
//
|
|
|
|
|
// each user has its own because a UNI may choose to tell different people
|
|
|
|
|
// different things.. in fact, a UNL may have reasons to propose different
|
|
|
|
|
// UNIs, too, but right now we're only being half consequent.. also there
|
|
|
|
|
// are no known applications making use of this feature anyhow ;)
|
|
|
|
|
volatile mapping uni2unl;
|
|
|
|
|
# ifdef USE_THE_RESOURCE
|
|
|
|
|
volatile string bare;
|
|
|
|
|
# endif
|
|
|
|
|
#endif //}}}
|
|
|
|
|
|
|
|
|
|
volatile string identification;
|
|
|
|
|
volatile mixed _tag, _source_tag;
|
|
|
|
|
|
|
|
|
|
#ifdef TAGGING
|
|
|
|
|
volatile protected mapping _tags;
|
|
|
|
|
|
|
|
|
|
/* currently, only net/jabber needs this */
|
|
|
|
|
void chain_callback(mixed tag, mixed chain_callback) {
|
|
|
|
|
if (_tags[tag])
|
|
|
|
|
_tags[tag] = ({ chain_callback }) + _tags[tag];
|
|
|
|
|
else
|
|
|
|
|
_tags[tag] = ({ chain_callback });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mixed execute_callback(mixed tag, mixed cbargs) {
|
|
|
|
|
mixed ret, cbchain;
|
|
|
|
|
// API: return 0 if there was no callback, callback return value or 1 if successful ?
|
|
|
|
|
unless(_tags[tag]) return 0;
|
|
|
|
|
ret = cbargs;
|
|
|
|
|
cbchain = _tags[tag];
|
|
|
|
|
m_delete(_tags, tag);
|
|
|
|
|
foreach(mixed cb : cbchain) {
|
|
|
|
|
ret = apply(cb, ret);
|
|
|
|
|
}
|
|
|
|
|
return ret || 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef ENTITY_STATE //{{{
|
|
|
|
|
inherit NET_PATH "state";
|
|
|
|
|
|
|
|
|
|
// lpc really needs an inline modifier!
|
|
|
|
|
# define STATE(context) ((context) ? _cstate : _state)
|
|
|
|
|
# define OSTATE(target) (member(_ostate, target) \
|
|
|
|
|
? _ostate[target] \
|
|
|
|
|
: _ostate[target] = ([ ]))
|
|
|
|
|
# define OMEMORY(target) (member(_memory, target) \
|
|
|
|
|
? _memory[target] \
|
|
|
|
|
: _memory[target] = m_allocate(0, 2))
|
|
|
|
|
#endif //}}}
|
|
|
|
|
|
2009-01-26 20:12:53 +00:00
|
|
|
|
#ifndef _flag_disable_module_trust
|
2009-01-26 19:21:29 +00:00
|
|
|
|
// first try to implement trust for remote ( means.. not a direct peer
|
|
|
|
|
// inside the friendsnet ) objects
|
|
|
|
|
volatile mapping _trust;
|
|
|
|
|
|
|
|
|
|
// returns -1 if there was no information for somebody...
|
|
|
|
|
// otherwise the level of trust \elem [0,10]
|
|
|
|
|
//
|
|
|
|
|
// is supposed to be overloaded by person/place for ignrores/friendships
|
|
|
|
|
// and banned people
|
|
|
|
|
int get_trust(string who, string by_whom) {
|
|
|
|
|
mixed t;
|
|
|
|
|
unless (member(_trust, who)) return -1;
|
|
|
|
|
|
|
|
|
|
if (by_whom) {
|
|
|
|
|
if (t = psyc_object(by_whom)) by_whom = t->qName();
|
|
|
|
|
|
|
|
|
|
unless (member(_trust[who], by_whom)) return -1;
|
|
|
|
|
t = get_trust(by_whom, 0);
|
|
|
|
|
|
|
|
|
|
if (t <= 0)
|
|
|
|
|
return 0;
|
|
|
|
|
return _trust[who][by_whom]* t / MAXIMUM_TRUST;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// should be cache the maximum.. maybe yes.. otherwise we end up
|
|
|
|
|
// calculating this stuff over and over again
|
|
|
|
|
return max(m_values(_trust[who]));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
sendmsg(target, mc, data, vars, source, showingLog, callback) {
|
|
|
|
|
string t;
|
|
|
|
|
|
|
|
|
|
P3(("uni(%O): sendmsg(%O, %O, %O, %O, %O, %O)\n", ME, target, mc, data, vars, source, showingLog))
|
|
|
|
|
|
|
|
|
|
#ifdef UNL_ROUTING //{{{
|
|
|
|
|
if (t = uni2unl[target]) {
|
|
|
|
|
// maybe we should keep the _identification of the target somewhere
|
|
|
|
|
// in vars. but where? _target_identification ? and who needs that?
|
|
|
|
|
//
|
|
|
|
|
// great, if I ping xmpp:fippo@amessage.de this makes
|
2010-02-21 08:36:11 +00:00
|
|
|
|
// it xmpp:fippo@amessage.de/foo, but I DONT WANT THAT!
|
2010-02-21 10:09:52 +00:00
|
|
|
|
//
|
|
|
|
|
// also in order to allow for multiple psyc clients we need
|
|
|
|
|
// this if here, but i think we should rather ensure these
|
|
|
|
|
// candidates are not in uni2unl[].. --lynX
|
|
|
|
|
#if 1 //FIXME
|
2010-02-21 08:36:11 +00:00
|
|
|
|
if (!objectp(target) || (objectp(target)
|
|
|
|
|
&& target->vQuery("scheme") != "psyc"))
|
2010-02-21 10:09:52 +00:00
|
|
|
|
#endif
|
2010-02-14 01:58:06 +00:00
|
|
|
|
target = t;
|
2009-01-26 19:21:29 +00:00
|
|
|
|
}
|
|
|
|
|
#endif //}}}
|
|
|
|
|
#ifdef FORK //{{{
|
|
|
|
|
# if 0
|
|
|
|
|
if (vars) { // shouldn't _count be set for msgs with empty vars, too?
|
|
|
|
|
// these are overwritten by source, target. maybe we should stop
|
|
|
|
|
// objects from reusing vars since that could easily be abused
|
|
|
|
|
// to broatcast junk.
|
|
|
|
|
m_delete(vars, "_source");
|
|
|
|
|
m_delete(vars, "_target");
|
|
|
|
|
// <lynX> why are you manually deleting some vars here which are also
|
|
|
|
|
// defined in isRouting and do not delete _context or _counter?
|
|
|
|
|
} else vars = ([ ]);
|
|
|
|
|
# endif
|
|
|
|
|
#endif //}}}
|
|
|
|
|
if (mappingp(vars)) {
|
|
|
|
|
// uhm. better rename simul-efun-sendmsg and let sendmsg be defined in
|
|
|
|
|
// each object, doing return real_sendmsg(...); .. agree, but have to
|
|
|
|
|
// figure out a name for it.. maybe system_sendmsg? or submitmsg?
|
|
|
|
|
if (_tag && target == _source_tag &&! vars["_INTERNAL_tag_skip"]) {
|
|
|
|
|
unless (vars) vars = ([]);
|
|
|
|
|
vars["_tag_reply"] = _tag;
|
|
|
|
|
unless (vars["_INTERNAL_tag_again"]) _tag = 0;
|
|
|
|
|
}
|
|
|
|
|
#if 1 //DEBUG > 2
|
|
|
|
|
} else {
|
|
|
|
|
// dump trace w/out error...!?
|
|
|
|
|
P1(("uni:sendmsg(%O) called without vars\n", mc))
|
|
|
|
|
// vars = ([ ]); -- server works better with debug? no way!
|
|
|
|
|
//raise_error("uni:sendmsg called without vars\n");
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
#ifdef TAGGING
|
|
|
|
|
if (callback) {
|
|
|
|
|
// if the caller supplies a _tag, it is responsible for
|
|
|
|
|
// uniqueness within the user object
|
|
|
|
|
if (!vars["_tag"]) {
|
|
|
|
|
while(_tags[vars["_tag"] = RANDHEXSTRING]);
|
|
|
|
|
}
|
|
|
|
|
_tags[vars["_tag"]] = ({ callback });
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return library_object()->sendmsg(target, mc, data, vars, source, showingLog);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef EXPERIMENTAL
|
|
|
|
|
// it's here, it may be nice or not.. we don't know..
|
|
|
|
|
// because nothing is using it
|
|
|
|
|
// <fippo> nothing is using it, because commiting code
|
|
|
|
|
// without any infrastructure is pointless.
|
|
|
|
|
mapping reply(mapping vars) {
|
|
|
|
|
mapping rvars = ([]);
|
|
|
|
|
|
|
|
|
|
if (member(vars, "_tag"))
|
|
|
|
|
rvars["_tag_reply"] = vars["_tag"];
|
|
|
|
|
if (member(vars, "_INTERNAL_source_resource"))
|
|
|
|
|
rvars["_INTERNAL_target_resource"] = vars["_INTERNAL_source_resource"];
|
|
|
|
|
if (member(vars, "_INTERNAL_target_resource"))
|
|
|
|
|
rvars["_INTERNAL_source_resource"] = vars["_INTERNAL_target_resource"];
|
|
|
|
|
|
|
|
|
|
rvars["_target"] = vars["_source_identification_reply"] || vars["_source_reply"] || vars["_source"];
|
|
|
|
|
return rvars;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
msg(source, mc, data, vars) {
|
|
|
|
|
string t, sid;
|
|
|
|
|
|
|
|
|
|
P3(("uni::msg(%O, %O, %O, %O)\n", source, mc, data, vars))
|
|
|
|
|
#ifdef _flag_log_flow_messages
|
|
|
|
|
log_file("FLOW_MESSAGES", "%s %O ( %O <20> %O )\n", mc, strlen(data),
|
|
|
|
|
ME, source);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef UNL_ROUTING //{{{
|
|
|
|
|
# ifdef USE_THE_RESOURCE
|
|
|
|
|
// too expensive to m_delete if this is going to be re-set anytime soon
|
|
|
|
|
if (bare) bare = uni2unl[bare] = 0;
|
|
|
|
|
# endif
|
|
|
|
|
#endif //}}}
|
|
|
|
|
#ifdef CAST_STATE
|
|
|
|
|
// FIXME: we've got the cast state already made up by the
|
|
|
|
|
// cslave, but we need to route it down to the client...
|
|
|
|
|
// if there is any!
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// deletes _tag if none is available
|
|
|
|
|
if (_tag = vars["_tag"]) {
|
|
|
|
|
P2(("tag %O for %O stored in %O\n", _tag, source, ME))
|
|
|
|
|
_source_tag = source;
|
|
|
|
|
}
|
|
|
|
|
#ifdef TAGGING
|
|
|
|
|
// allow _tag to trigger this? this is to circumvent some bug
|
|
|
|
|
// that doesn't provide us with _tag_reply as it should.. huh?
|
|
|
|
|
// but maybe it's okay anyway.. we'll see
|
|
|
|
|
//
|
|
|
|
|
// <fippo>: it is a bug on psyced.org only. As soon as you fix it,
|
|
|
|
|
// I will happily remove the || _tag
|
|
|
|
|
// <fippo>: not on psyced.org only. seems to happen if a second remote
|
|
|
|
|
// joins
|
|
|
|
|
if ((t = vars["_tag_reply"] || vars["_tag"]) && _tags[t]) {
|
|
|
|
|
if (execute_callback(t,
|
|
|
|
|
({ source, mc, data, vars }))) return 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef FORK //{{{
|
|
|
|
|
mixed route = vars["_context"] || source;
|
|
|
|
|
|
|
|
|
|
unless(member(_icount, route)) _icount[route] = 0;
|
|
|
|
|
if (member(vars, "_count")
|
|
|
|
|
&& vars["_count"] != to_string(_icount[route]++)) {
|
|
|
|
|
sendmsg(route, 0, 0, ([ "_count" : 0 ]));
|
|
|
|
|
if (vars["_count"] == "0") {
|
|
|
|
|
Reset(route, vars["_context"]);
|
|
|
|
|
_icount[route] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m_delete(vars, "_count");
|
|
|
|
|
m_delete(vars, "_target"); // TODO:: find out if there's a better solution,
|
|
|
|
|
// like not having target in the vars at all.
|
|
|
|
|
|
|
|
|
|
if (member(STATE(vars["_context"]), route)) {
|
|
|
|
|
//vars = _state[source] + vars; // overwrite by :
|
|
|
|
|
P3(("STATE-VARS: %O\n", STATE(vars["_context"])[route]));
|
|
|
|
|
foreach (mixed x, mixed y : STATE(vars["_context"])[route])
|
|
|
|
|
unless (member(vars, x)) vars[x] = y;
|
|
|
|
|
}
|
|
|
|
|
#else //FORK }}}
|
2009-01-26 20:12:53 +00:00
|
|
|
|
# ifndef _flag_disable_module_authentication
|
2009-01-26 19:21:29 +00:00
|
|
|
|
// person.c only calls this for stringp(source), so why check here again?
|
|
|
|
|
// because place/basic.c calls this for all sorts of sources. why this
|
|
|
|
|
// inconsistency? and what about local string sources? TODO
|
|
|
|
|
unless (objectp(source)) {
|
|
|
|
|
if (abbrev("_notice_authentication", mc)) {
|
|
|
|
|
string l = vars["_location"];
|
|
|
|
|
unless (qExists(l)) return 0;
|
|
|
|
|
#ifdef UNL_ROUTING //{{{
|
|
|
|
|
uni2unl[source] = l;
|
|
|
|
|
#endif //}}}
|
|
|
|
|
// i guess this should have been here.. let's try that
|
|
|
|
|
register_location(l, source, 1);
|
|
|
|
|
while (qSize(l))
|
|
|
|
|
apply(#'msg, shift(l));
|
|
|
|
|
qDel(l);
|
|
|
|
|
return 0;
|
|
|
|
|
} else if (abbrev("_error_invalid_authentication", mc)) {
|
|
|
|
|
string l = vars["_location"];
|
|
|
|
|
P1(("_error_invalid_authentication (%O) for %O (location does "
|
|
|
|
|
"%Oexist)\n", ME, l, qExists(l) ? "" : "not"))
|
|
|
|
|
if (qExists(l)) qDel(l);
|
|
|
|
|
return 0;
|
|
|
|
|
} else if (sid = vars["_source_identification"]) {
|
|
|
|
|
// && !(abbrev("_status_place_identification", mc)
|
|
|
|
|
// || abbrev("_status_description_person", mc))
|
|
|
|
|
// && !abbrev("_status", mc))
|
|
|
|
|
if (sid == source) {
|
|
|
|
|
t = 0;
|
|
|
|
|
// redundant _source_identification, pls fix the sender
|
|
|
|
|
// <fippo> I like debug code breaking...
|
|
|
|
|
//log_file("LUNITAR", "%O in %O (%O)\n", sid, ME, v("agent"));
|
|
|
|
|
// return in this case?
|
|
|
|
|
}
|
|
|
|
|
#ifdef UNL_ROUTING //{{{
|
|
|
|
|
else if (uni2unl[sid] == source) t = sid;
|
|
|
|
|
# ifdef USE_THE_RESOURCE
|
|
|
|
|
// our jabber gateway doesn't lie about identifications.
|
|
|
|
|
// just use it instead of the UNR
|
|
|
|
|
else if (vars["_INTERNAL_identification"]) {
|
|
|
|
|
// this must not get active if _nick_place is set!
|
|
|
|
|
if (!vars["_nick_place"]) {
|
|
|
|
|
bare = t = sid;
|
|
|
|
|
uni2unl[t] = source;
|
|
|
|
|
P2(("USE_THE_RESOURCE in %O: use %O instead of %O\n",
|
|
|
|
|
ME, t, source))
|
|
|
|
|
} else
|
|
|
|
|
t = source;
|
|
|
|
|
}
|
|
|
|
|
# endif
|
|
|
|
|
#endif //}}}
|
|
|
|
|
else {
|
|
|
|
|
// this will not trigger a systemwide _request_authentication
|
|
|
|
|
t = lookup_identification(source);
|
|
|
|
|
if (t == sid) {
|
|
|
|
|
#ifdef UNL_ROUTING //{{{
|
|
|
|
|
uni2unl[t] = source;
|
|
|
|
|
#endif //}}}
|
|
|
|
|
} else unless (objectp(t)) {
|
|
|
|
|
// we should intercept when the UNI is claimed to be on the
|
|
|
|
|
// same server where the location is - that's always legitimate
|
|
|
|
|
// and at the same time plain humbug. so we can either accept
|
|
|
|
|
// it or reject it. we shouldn't issue a _request_authentication
|
|
|
|
|
// in that case. TODO: FIXME QUICK ;)
|
|
|
|
|
P3((">>> qExists %O %O\n", qExists(source), source))
|
|
|
|
|
unless (qExists(source)) {
|
|
|
|
|
P1(("%O sending _request_authentication to %O for %O\n",
|
|
|
|
|
ME, sid, source))
|
|
|
|
|
library_object()->sendmsg(sid, "_request_authentication", 0,
|
|
|
|
|
([ "_location" : source ]));
|
|
|
|
|
qInit(source, 30, 5);
|
|
|
|
|
}
|
|
|
|
|
enqueue(source, ({ source, mc, data, vars }));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (t) {
|
2009-01-26 20:12:53 +00:00
|
|
|
|
# if 1
|
2009-01-26 19:21:29 +00:00
|
|
|
|
// we can either decide to see our own locations as source
|
|
|
|
|
// since that's what the code in person.c already does, we'll
|
|
|
|
|
// try this option first
|
|
|
|
|
if (t == ME) vars["_source_identification"] = ME;
|
|
|
|
|
else {
|
|
|
|
|
// is there any known reason why this was missing?
|
|
|
|
|
vars["_location"] = source;
|
|
|
|
|
m_delete(vars, "_source_identification");
|
|
|
|
|
source = t;
|
|
|
|
|
// don't trust what the client says
|
|
|
|
|
if (objectp(t)) vars["_nick"] = t->qName();
|
|
|
|
|
// user.c does something very similar - so this
|
|
|
|
|
// shouldn't be necessary, yet if i remove that
|
|
|
|
|
// line a client can propose its own _nick and
|
|
|
|
|
// will be successful. hm!
|
|
|
|
|
}
|
2009-01-26 20:12:53 +00:00
|
|
|
|
# else //{{{
|
2009-01-26 19:21:29 +00:00
|
|
|
|
// or copy them into a var, then compare everywhere
|
|
|
|
|
// this requires a rewrite of all of the v("locations") code
|
|
|
|
|
vars["_location"] = source;
|
|
|
|
|
m_delete(vars, "_source_identification");
|
|
|
|
|
source = t;
|
|
|
|
|
// don't trust what the client says
|
|
|
|
|
if (objectp(t)) vars["_nick"] = t->qName();
|
2009-01-26 20:12:53 +00:00
|
|
|
|
# endif //}}}
|
2009-01-26 19:21:29 +00:00
|
|
|
|
// do we really want to delete it also in the else case?
|
|
|
|
|
} else m_delete(vars, "_source_identification");
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-01-26 20:12:53 +00:00
|
|
|
|
# endif // _flag_disable_module_authentication
|
2009-01-26 19:21:29 +00:00
|
|
|
|
#endif // !FORK
|
|
|
|
|
|
2009-01-26 20:12:53 +00:00
|
|
|
|
#ifndef _flag_disable_module_trust
|
2009-01-26 19:21:29 +00:00
|
|
|
|
// this mechanism does not work for objectp(source) because uni::msg is not
|
|
|
|
|
// called for objects. TODO
|
|
|
|
|
// this stuff works alot like _request_auth.. i still think there might be
|
|
|
|
|
// some code to share
|
|
|
|
|
if (member(vars, "_trustee") && vars["_trustee"]) {
|
|
|
|
|
string snicker = objectp(source) ? vars["_nick"] : source;
|
|
|
|
|
string trustee = vars["_trustee"];
|
|
|
|
|
int trustiness = get_trust(snicker, trustee);
|
|
|
|
|
|
|
|
|
|
P4(("trustee: %O -> %O\n", trustee, trustiness))
|
|
|
|
|
if (trustiness != -1) {
|
|
|
|
|
vars["_trust"] = trustiness;
|
|
|
|
|
} else { // do we want to check for get_trust(source) first.. maybe
|
|
|
|
|
// he is a friend..
|
|
|
|
|
string trustee_nick = trustee;
|
|
|
|
|
//
|
|
|
|
|
// TODO we dont even need to ask the trustee if we dont
|
|
|
|
|
// trust him anyway...
|
|
|
|
|
if (is_formal(trustee)) {
|
|
|
|
|
mixed *u = parse_uniform(trustee);
|
|
|
|
|
|
|
|
|
|
unless (u) {
|
|
|
|
|
return 1;
|
|
|
|
|
// evil, there is no trustiness
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// an ideal psyc parser would recognize local _trustee
|
|
|
|
|
// and have it replaced by object.. but that's not the case
|
|
|
|
|
// we _could_ however do that by using _uniform_trustee
|
|
|
|
|
// and doing is_localhost on all _uniform's at parsing time
|
2009-03-04 10:27:19 +00:00
|
|
|
|
if (is_localhost(u[UHost])) trustee_nick = u[UNick];
|
2009-01-26 19:21:29 +00:00
|
|
|
|
}
|
|
|
|
|
if (get_trust(trustee_nick, 0) < MINIMUM_TRUST) return 1;
|
|
|
|
|
// entweder trustee ist ein local nick, dann kriegen wir den
|
|
|
|
|
// get_trust, aber sendmsg failed hier unten.. oder trustee
|
|
|
|
|
// ist eine uni, dann kann er zwar senden, findet die person
|
|
|
|
|
// aber nicht im ppl[]
|
|
|
|
|
|
|
|
|
|
unless (qExists("t"+snicker)) {
|
|
|
|
|
qInit("t"+snicker, 30, 5);
|
|
|
|
|
enqueue("t"+snicker, ({ source, mc, data, vars }));
|
|
|
|
|
P4(("%O no trustiness for %O in %O. Queue: %O\n",
|
|
|
|
|
ME, snicker, _trust, qDebug()))
|
|
|
|
|
// seeing this message is never useful, really
|
|
|
|
|
// the question is answered automatically, so a user
|
|
|
|
|
// would only get confused..
|
|
|
|
|
sendmsg(trustee, "_request_trustiness",
|
|
|
|
|
0 && "Do you trust [_identification] also known as [_nick]?",
|
|
|
|
|
([ "_identification" : source, "_nick" : MYNICK ]));
|
|
|
|
|
// we are lazy here.. but one trust request must be enough..
|
|
|
|
|
// for now
|
|
|
|
|
} else
|
|
|
|
|
enqueue("t"+snicker, ({ source, mc, data, vars }));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (abbrev("_notice_trustiness", mc)) {
|
|
|
|
|
int trustiness = to_int(vars["_trustiness"]);
|
|
|
|
|
mixed l = vars["_identification"];
|
|
|
|
|
string s = objectp(source) ? vars["_nick"] : source;
|
|
|
|
|
|
|
|
|
|
if (objectp(l)) l = l->qName();
|
|
|
|
|
P4(("%O: %O got a trustiness of %d from %O.\n", ME,
|
|
|
|
|
l, trustiness, source))
|
|
|
|
|
unless (l) {
|
|
|
|
|
P0(("%O got %O without _identification\n", ME, mc))
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!member(_trust, l)) {
|
|
|
|
|
_trust[l] = ([ s : trustiness ]);
|
|
|
|
|
} else {
|
|
|
|
|
_trust[l][s] = trustiness;
|
|
|
|
|
}
|
|
|
|
|
l = "t"+l;
|
|
|
|
|
P4(("%O: Queue %O from %O.\n", ME, l, qDebug()))
|
|
|
|
|
if (qExists(l)) {
|
|
|
|
|
while (qSize(l))
|
|
|
|
|
apply(#'msg, shift(l));
|
|
|
|
|
qDel(l);
|
|
|
|
|
}
|
|
|
|
|
// dont drop the packet.. maybe we want to see this information
|
|
|
|
|
// return 0;
|
|
|
|
|
} else if (abbrev("_request_trustiness", mc)) {
|
|
|
|
|
if (get_trust(objectp(source) ? vars["_nick"]
|
|
|
|
|
: source, 0) < MINIMUM_TRUST) {
|
|
|
|
|
sendmsg(source, "_failure_trustiness",
|
|
|
|
|
"I dont know anything about [_identification]!", ([
|
|
|
|
|
"_identification" : vars["_identification"]
|
|
|
|
|
]));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int trustiness = get_trust(objectp(vars["_identification"]) ?
|
|
|
|
|
vars["_identification"]->qName() : vars["_identification"], 0);
|
|
|
|
|
P4(("%O: %O asked me for trustiness (%d) of %O.\n", ME, source,
|
|
|
|
|
trustiness, vars["_identification"]))
|
|
|
|
|
if (-1 != trustiness) {
|
|
|
|
|
|
|
|
|
|
sendmsg(source, "_notice_trustiness", "I trust [_identification] like [_trustiness] times bigger than others.",
|
|
|
|
|
([ "_identification" : vars["_identification"],
|
|
|
|
|
"_nick" : MYNICK,
|
|
|
|
|
"_trustiness" : trustiness ]));
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-01-26 20:12:53 +00:00
|
|
|
|
#endif // _flag_disable_module_trust
|
2009-01-26 19:21:29 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
create() {
|
|
|
|
|
// would be nice to skip this for blueprints, but at this point we have
|
|
|
|
|
// no way to distinguish original places from blueprints - we have no
|
|
|
|
|
// qName() yet - so all we could do would be to look at our object path.
|
|
|
|
|
//unless (clonep() && qName()) return; // do not initialize blueprints
|
|
|
|
|
// a different approach would be to rename this into eCreate() and have
|
|
|
|
|
// it called in the right places. TODO (cleanup)
|
|
|
|
|
#ifdef UNL_ROUTING //{{{
|
|
|
|
|
ASSERT("entity::create() !uni2unl", !uni2unl, uni2unl)
|
|
|
|
|
uni2unl = ([ ]);
|
|
|
|
|
#endif //}}}
|
2009-01-26 20:12:53 +00:00
|
|
|
|
#ifndef _flag_disable_module_trust
|
2009-01-26 19:21:29 +00:00
|
|
|
|
_trust = ([ ]);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef ENTITY_STATE //{{{
|
|
|
|
|
// wieso packen wir die counter nicht mit ins state-array. also
|
|
|
|
|
// mehrdimensional ?
|
|
|
|
|
_state = ([ ]);
|
|
|
|
|
_ostate = ([ ]);
|
|
|
|
|
_cstate = ([ ]);
|
|
|
|
|
_icount = ([ ]);
|
|
|
|
|
_count = ([ ]);
|
|
|
|
|
_memory = ([ ]);
|
|
|
|
|
temp = ([]);
|
|
|
|
|
#endif //}}}
|
|
|
|
|
#ifdef NEW_QUEUE
|
|
|
|
|
qCreate();
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef TAGGING
|
|
|
|
|
_tags = ([ ]);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef ENTITY_STATE //{{{
|
|
|
|
|
|
|
|
|
|
// reset the state.. which means: _count == 0
|
|
|
|
|
void Reset(mixed source, mixed isContext) {
|
|
|
|
|
|
|
|
|
|
PT(("Reset(%O) in %O\n", source, ME));
|
|
|
|
|
|
|
|
|
|
STATE(isContext)[source] = ([ ]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Assign(mixed source, string key, mixed value, mixed isContext) {
|
|
|
|
|
mapping state = STATE(isContext);
|
|
|
|
|
|
|
|
|
|
PT(("Assign(%O, %O, %O) in %O\n", source, key, value, ME));
|
|
|
|
|
unless (member(state, source)) {
|
|
|
|
|
state[source] = ([]);
|
|
|
|
|
}
|
|
|
|
|
if (value) {
|
|
|
|
|
state[source][key] = value;
|
|
|
|
|
} else m_delete(state[source], key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Augment(mixed source, string key, mixed value, mixed isContext) {
|
|
|
|
|
mapping state = STATE(isContext);
|
|
|
|
|
|
|
|
|
|
PT(("Augment(%O, %O, %O) in %O\n", source, key, value, ME));
|
|
|
|
|
unless (member(state, source)) {
|
|
|
|
|
state[source] = ([]);
|
|
|
|
|
}
|
|
|
|
|
_augment(state[source], key, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Diminish(mixed source, string key, mixed value, mixed isContext) {
|
|
|
|
|
int i;
|
|
|
|
|
mapping state = STATE(isContext);
|
|
|
|
|
|
|
|
|
|
PT(("Diminish(%O, %O, %O) in %O\n", source, key, value, ME));
|
|
|
|
|
if (member(state, source)) {
|
|
|
|
|
_diminish(state[source], key, value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int outstate(string target, string key, mixed value, int hascontext) {
|
|
|
|
|
mapping timemachine = OMEMORY(target);
|
|
|
|
|
mapping state = OSTATE(target);
|
|
|
|
|
mapping t = temp[target];
|
|
|
|
|
int mod;
|
|
|
|
|
|
|
|
|
|
if (hascontext) {
|
|
|
|
|
//PT(("%O sends messages in a context without using group/master.c.", ME))
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (key[0] == '_') {
|
|
|
|
|
mod = ':';
|
|
|
|
|
} else {
|
|
|
|
|
mod = key[0];
|
|
|
|
|
key = key[1..];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unless (t) t = temp[target] = ([ ]);
|
|
|
|
|
|
|
|
|
|
unless (unused) unused = copy(state);
|
|
|
|
|
m_delete(unused, key);
|
|
|
|
|
|
|
|
|
|
switch(mod) {
|
|
|
|
|
case ':':
|
|
|
|
|
if (timemachine[key, 1] == -1) break;
|
|
|
|
|
if (member(timemachine, key)) {
|
|
|
|
|
if (timemachine[key] == value) {
|
|
|
|
|
if (timemachine[key, 1] == STATE_MAX2) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (timemachine[key, 1] == STATE_MIN2) {
|
|
|
|
|
t["="+key] = value;
|
|
|
|
|
state[key] = value;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
timemachine[key, 1]++;
|
|
|
|
|
} else if (timemachine[key, 1] - 1 == STATE_MIN2) {
|
|
|
|
|
t["="+key] = "";
|
|
|
|
|
m_add(timemachine, key, value, 1);
|
|
|
|
|
} else if (timemachine[key, 1] <= STATE_MIN2) {
|
|
|
|
|
m_add(timemachine, key, value, 1);
|
|
|
|
|
} else timemachine[key, 1]--;
|
|
|
|
|
} else m_add(timemachine, key, value, 1);
|
|
|
|
|
break;
|
|
|
|
|
case '=':
|
|
|
|
|
if ("" == value) {
|
|
|
|
|
m_delete(state, key);
|
|
|
|
|
m_delete(timemachine, key);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (member(state, key) && state[key] == value) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
m_add(timemachine, key, value, -1);
|
|
|
|
|
state[key] = value;
|
|
|
|
|
break;
|
|
|
|
|
case '+':
|
|
|
|
|
_augment(state, key, value);
|
|
|
|
|
break;
|
|
|
|
|
case '-':
|
|
|
|
|
_diminish(state, key, value);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
raise_error("Illegal variable modifier in '" + key +
|
|
|
|
|
"' encountered in entity:outstate.\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mapping state(string target, int hascontext) {
|
|
|
|
|
mapping t, t2 = ([ ]);
|
|
|
|
|
mapping timemachine = OMEMORY(target);
|
|
|
|
|
|
|
|
|
|
if (hascontext) {
|
|
|
|
|
PT(("%O sends messages in a context without using group/master.c.", ME))
|
|
|
|
|
return ([]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (unused) {
|
|
|
|
|
foreach (string key : unused) {
|
|
|
|
|
// variables assigned manually are taken to be permanent.
|
|
|
|
|
if (timemachine[key, 1] != -1)
|
|
|
|
|
t2[":" + key] = "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unused = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t = temp[target] || ([ ]);
|
|
|
|
|
m_delete(temp, target);
|
|
|
|
|
|
|
|
|
|
// rock hard optimization
|
|
|
|
|
unless (sizeof(t))
|
|
|
|
|
return t2;
|
|
|
|
|
unless (sizeof(t2))
|
|
|
|
|
return t;
|
|
|
|
|
return t2 + t;
|
|
|
|
|
}
|
|
|
|
|
#endif // ENTITY_STATE }}}
|