1
0
Fork 0
mirror of git://git.psyced.org/git/psyced synced 2024-08-15 03:25:10 +00:00

let the past begone in cvs land. welcome to igit igit!

This commit is contained in:
PSYC 2009-01-26 20:21:29 +01:00
commit 4e601cf1c7
509 changed files with 77963 additions and 0 deletions

View file

@ -0,0 +1,25 @@
.cvsignore
_hesmo.c
_hsmo.c
_smo.c
_hemo.c
_hmo.c
_mo.c
_heso.c
_hso.c
_so.c
_heo.c
_ho.c
_o.c
_hesm.c
_hsm.c
_sm.c
_hem.c
_hm.c
_m.c
_hes.c
_hs.c
_s.c
_he.c
_h.c
_.c

5
world/net/place/_.c Normal file
View file

@ -0,0 +1,5 @@
// model '_' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#include "archetype.gen"

6
world/net/place/_h.c Normal file
View file

@ -0,0 +1,6 @@
// model '_h' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_HISTORY
#include "archetype.gen"

7
world/net/place/_he.c Normal file
View file

@ -0,0 +1,7 @@
// model '_he' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_HISTORY
#define PLACE_HISTORY_EXPORT
#include "archetype.gen"

8
world/net/place/_hem.c Normal file
View file

@ -0,0 +1,8 @@
// model '_hem' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_HISTORY
#define PLACE_HISTORY_EXPORT
#define PLACE_MASQUERADE
#include "archetype.gen"

9
world/net/place/_hemo.c Normal file
View file

@ -0,0 +1,9 @@
// model '_hemo' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_HISTORY
#define PLACE_HISTORY_EXPORT
#define PLACE_MASQUERADE
#define PLACE_OWNED
#include "archetype.gen"

8
world/net/place/_heo.c Normal file
View file

@ -0,0 +1,8 @@
// model '_heo' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_HISTORY
#define PLACE_HISTORY_EXPORT
#define PLACE_OWNED
#include "archetype.gen"

8
world/net/place/_hes.c Normal file
View file

@ -0,0 +1,8 @@
// model '_hes' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_HISTORY
#define PLACE_HISTORY_EXPORT
#define PLACE_SCRATCHPAD
#include "archetype.gen"

9
world/net/place/_hesm.c Normal file
View file

@ -0,0 +1,9 @@
// model '_hesm' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_HISTORY
#define PLACE_HISTORY_EXPORT
#define PLACE_SCRATCHPAD
#define PLACE_MASQUERADE
#include "archetype.gen"

10
world/net/place/_hesmo.c Normal file
View file

@ -0,0 +1,10 @@
// model '_hesmo' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_HISTORY
#define PLACE_HISTORY_EXPORT
#define PLACE_SCRATCHPAD
#define PLACE_MASQUERADE
#define PLACE_OWNED
#include "archetype.gen"

9
world/net/place/_heso.c Normal file
View file

@ -0,0 +1,9 @@
// model '_heso' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_HISTORY
#define PLACE_HISTORY_EXPORT
#define PLACE_SCRATCHPAD
#define PLACE_OWNED
#include "archetype.gen"

7
world/net/place/_hm.c Normal file
View file

@ -0,0 +1,7 @@
// model '_hm' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_HISTORY
#define PLACE_MASQUERADE
#include "archetype.gen"

8
world/net/place/_hmo.c Normal file
View file

@ -0,0 +1,8 @@
// model '_hmo' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_HISTORY
#define PLACE_MASQUERADE
#define PLACE_OWNED
#include "archetype.gen"

7
world/net/place/_ho.c Normal file
View file

@ -0,0 +1,7 @@
// model '_ho' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_HISTORY
#define PLACE_OWNED
#include "archetype.gen"

7
world/net/place/_hs.c Normal file
View file

@ -0,0 +1,7 @@
// model '_hs' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_HISTORY
#define PLACE_SCRATCHPAD
#include "archetype.gen"

8
world/net/place/_hsm.c Normal file
View file

@ -0,0 +1,8 @@
// model '_hsm' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_HISTORY
#define PLACE_SCRATCHPAD
#define PLACE_MASQUERADE
#include "archetype.gen"

9
world/net/place/_hsmo.c Normal file
View file

@ -0,0 +1,9 @@
// model '_hsmo' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_HISTORY
#define PLACE_SCRATCHPAD
#define PLACE_MASQUERADE
#define PLACE_OWNED
#include "archetype.gen"

8
world/net/place/_hso.c Normal file
View file

@ -0,0 +1,8 @@
// model '_hso' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_HISTORY
#define PLACE_SCRATCHPAD
#define PLACE_OWNED
#include "archetype.gen"

6
world/net/place/_m.c Normal file
View file

@ -0,0 +1,6 @@
// model '_m' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_MASQUERADE
#include "archetype.gen"

7
world/net/place/_mo.c Normal file
View file

@ -0,0 +1,7 @@
// model '_mo' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_MASQUERADE
#define PLACE_OWNED
#include "archetype.gen"

6
world/net/place/_o.c Normal file
View file

@ -0,0 +1,6 @@
// model '_o' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_OWNED
#include "archetype.gen"

6
world/net/place/_s.c Normal file
View file

@ -0,0 +1,6 @@
// model '_s' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_SCRATCHPAD
#include "archetype.gen"

7
world/net/place/_sm.c Normal file
View file

@ -0,0 +1,7 @@
// model '_sm' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_SCRATCHPAD
#define PLACE_MASQUERADE
#include "archetype.gen"

8
world/net/place/_smo.c Normal file
View file

@ -0,0 +1,8 @@
// model '_smo' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_SCRATCHPAD
#define PLACE_MASQUERADE
#define PLACE_OWNED
#include "archetype.gen"

7
world/net/place/_so.c Normal file
View file

@ -0,0 +1,7 @@
// model '_so' generated by '/home/lynx/bin/psyconf'
#define ESSENTIALS
#define PLACE_SCRATCHPAD
#define PLACE_OWNED
#include "archetype.gen"

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,101 @@
#!/usr/bin/perl
#
# generator of psyced place models using combinations of archetype flags.
# lynX 2007
my @opts, @predef, %map;
open(I, "archetype.gen") or die <<X;
$0: Cannot open archetype.gen. Need to be in my directory!
X
while (<I>) {
if (m!define\s(\w+)\s*//\s\[(.)\]!) {
if ($2 eq '+') {
push @predef, $1;
} else {
$map{$2} = $1;
push(@opts, $2);
}
} elsif (/^#endif/) {
last;
}
}
close I;
print "Generating archetype models...\n";
# print join("\n", @opts), "\n\n";
# print "$_\n" foreach ( %map );
open (O, ">../include/place.i") or die $!;
print O <<X;
// generated by '$0': place.i for place.gen
X
my $file = '';
foreach $o (@opts) {
print O <<X;
#ifdef $map{$o}
# define O$o "$o"
#else
# define O$o ""
#endif
X
$file .= " O$o";
}
print O <<X;
inherit NET_PATH "place/_"$file;
X
$predef = '';
foreach $p (@predef) {
$predef .= "#define $p\n";
}
open(IG, ">.cvsignore") or print <<X;
Warning: cannot create .cvsignore. Well, doesn't matter.
X
# funny how it likes to see itself in there
print IG ".cvsignore\n";
my $bits = 1 + $#opts;
for ($v = 1 << $bits; $v;) {
$v--;
$f = '';
$model = '';
for ($i = 0; $i < $bits; $i++) {
if ($v & 1 << $i) {
my $o = $opts[$i];
$f .= $o;
$model .= "#define $map{$o}\n";
}
}
# special case: skip all exports without history
next if $f =~ /^e/;
# same special case is also handled in place.gen
printf " (%02d _%s)", $v, $f;
#print " ($v _$f)";
print IG "_$f.c\n";
open (O, ">_$f.c") or die $!;
# proud and noisy.. for a week or two at least ;)
#echo loading model '_$f' generated by '$0'
print O <<X;
// model '_$f' generated by '$0'
#define ESSENTIALS
$model
#include "archetype.gen"
X
# used to output $predef but it's easier to
# have archetype.gen sort out ESSENTIALS
close O;
}
close IG;
print "\nModel creation completed successfully.\n";
1; # this just so that psyconf can use it

4
world/net/place/basic.c Normal file
View file

@ -0,0 +1,4 @@
// $Id: basic.c,v 1.356 2007/09/08 21:18:07 lynx Exp $ // vim:syntax=lpc
#define BASIC
#include "archetype.gen"

View file

@ -0,0 +1,7 @@
// $Id: default.c,v 1.2 2007/09/08 21:25:20 lynx Exp $
//
// the room that gets cloned when there is no specific program available.
// don't inherit this.
//
#define DEFAULT
#include "archetype.gen"

82
world/net/place/gamespy.c Normal file
View file

@ -0,0 +1,82 @@
// $Id: gamespy.c,v 1.13 2008/01/05 12:42:17 lynx Exp $ // vim:syntax=lpc
//
// gamespy gateway in a room, or something
//
#include <net.h>
#include <person.h>
#include <status.h>
inherit NET_PATH "place/owned";
mapping servers;
void create() {
if (!servers) servers = ([]);
::create();
}
cmd(a, args, b, source, vars) {
// TODO: multiline-sachen irgendwie
D2(D("===========================\n");)
//unless (source) source = previous_object();
switch (a) {
case "add":
unless (qAide(SNICKER)) return;
if(!add(args)) {
sendmsg(source, "_warning_usage_gamespy_add",
"Usage: /add «gametype» «ip»:«port» [«name»]");
} else {
castmsg(source, "_notice_gamespy_added",
"Successfully added [_type]-Server [_host]",
([ "_type" : args[1],
"_host" : args[2],
]));
}
return 1;
case "delete":
case "del":
return 1;
case "server":
case "serverinfo":
if(sizeof(args) < 2) {
sendmsg(source, "_warning_usage_gamespy_info",
"Usage: /info «ip»:«port» OR: /info «name»");
return 1;
} else {
mapping info = DAEMON_PATH "gameserv"->info(args[1]);
if(!sizeof(m_indices(info))) {
sendmsg(source, "_error_gamespy_info",
"I dont know that gameserver! Use /add to add it!");
return 1;
}
sendmsg(source, "_notice_gamespy_info",
"================\nhost\t[_host]:[_port]\n"
"name\t[_name]\nmapname\t[_map]\n"
"players\t[_players]/[_maxplayers]",
info);
return 1;
}
case "servers":
case "listservers":
D2(D(DAEMON_PATH "gameserv"->list_servers());)
return 1;
}
return ::cmd(a, args, b, source, vars);
}
add(args) {
array(string) host;
if(sizeof(args) < 3)
return 0;
host = explode(args[2],":");
if(sizeof(host) != 2)
return 0;
if(sizeof(args) >= 4) {
DAEMON_PATH "gameserv"->add_server(args[1],host[0],to_int(host[1]),args[3]);
} else {
DAEMON_PATH "gameserv"->add_server(args[1],host[0],to_int(host[1]));
}
return 1;
}

View file

@ -0,0 +1,71 @@
// $Id: junction.c,v 1.22 2008/03/28 20:05:44 lynx Exp $ // vim:syntax=lpc
//
// quick attempt at glueing up master and slave to obtain a junction
// node in a simple tree-form multicast structure. it is more advanced
// than irc, because each place has its own tree, but it's
// still not as smart as a routing multicast approach.. -lynX
#include <net.h>
#include <person.h>
#include <status.h>
inherit NET_PATH "place/master";
inherit NET_PATH "place/slave";
histClear(a, b, source, vars) { return "master"::histClear(a, b, source, vars); }
memberInfo(person) { return "slave"::memberInfo(person); }
mixed isValidRelay(mixed x) {
return "slave"::isValidRelay(x) || "master"::isValidRelay(x); }
#ifndef QUIET_REMOTE_MEMBERS
castmsg(source, mc, data, vars) {
if (objectp(source)
&& (abbrev("_request_place_enter", mc)
|| abbrev("_request_enter", mc)
|| abbrev("_request_context", mc)
|| abbrev("_notice_context", mc)
|| abbrev("_notice_place_enter", mc)
|| abbrev("_notice_place_leave", mc)
|| abbrev("_request_leave", mc))) {
return "slave"::castmsg(source, mc, data, vars);
}
return "master"::castmsg(source, mc, data, vars);
}
castPresence(source, mc, data, vars) {
if (source == master || vars["_source_relay"] == master) {
return "master"::castmsg(ME, mc, data
? data
: "[_nick] enters [_nick_place].",
vars + (stringp(source) && is_formal(source)
? ([]) : ([ "_source_relay" : source ])));
}
return 0;
}
#endif
msg(source, mc, data, vars) {
P1(("junction:msg(%O, %O, %O, %O)\n", source, mc, data, vars))
unless (source == master
|| vars["_source_relay"] == master
|| vars["_context"] == master
|| mc == "_request_link") {
return "slave"::msg(source, mc, data, vars);
} else {
return "master"::msg(source, mc, data, vars);
}
// going thru both probably results in calling "storic"::msg twice
}
reboot(reason, restart, pass) {
"master"::reboot(reason, restart, pass);
return "slave"::reboot(reason, restart, pass);
}
qJunction() {
return 1;
}

View file

@ -0,0 +1,69 @@
// $Id: mailcast.c,v 1.7 2008/01/05 12:42:17 lynx Exp $
#include <net.h>
#include <person.h>
#include <status.h>
inherit NET_PATH "place/basic";
// noch nicht ganz klar ob das nicht einfach ein job der /history ist..
// und wir ganz generell hin und wieder mehrfache histories brauchen
//
array(mapping) mails = ({ });
//
// wieviele mails sollen gespeichert bleiben?
// ...waer gut, wenn man das im raumfile definieren koennt und hier bleibts..
//
#ifndef _limit_amount_history_mailcast
#define _limit_amount_history_mailcast 7
#endif
msg(source, mc, data, mapping vars) {
if (abbrev("_notice_email_delivered", mc)) {
// eine _notice_email_delivered wird im server-fenster angezeigt, nicht im raum..
// naja, der raum ist eh nicht zum chatten da..
// net/irc sollte das problem geschickter lösen dann..
// und nicht hier sowas komisches da:
castmsg(source, "_message_public_mail",
vars["_subject"]+":\n"+vars["_content"],
vars);
if (sizeof(mails) >= _limit_amount_history_mailcast) {
mails[0] = 0;
mails -= ({ 0 });
}
mails += ({ ([
"_source" : source,
"_subject" : vars["_subject"],
"_content" : vars["_content"]
]) });
save();
return;
}
return ::msg(source, mc, data, vars);
}
htget(prot, query, headers, qs, data, noprocess) {
htok(prot);
#ifndef STYLESHEET
# define STYLESHEET (v("_uniform_style") || "http://www.psyced.org/mail.css")
#endif
write("<link rel='stylesheet' type='text/css' href='"+
STYLESHEET +"'>\n");
// typically use textdb here to obtain different layouts
//
// write("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n"
// " <tr>\n <td>Source</td>\n <td>Subject</td>\n <td>Content</td>\n </tr>\n");
for (int i=sizeof(mails)-1; i>=0; i--) {
mapping mail = mails[i];
string t = htquote(mail["_content"]);
t = replace(t, "\n", "<br/>\n");
// write(" <tr>\n <td>"+ mail["_source"] +"</td>\n <td>"+ mail["_subject"] +"</td>\n <td>"+ t +"</td>\n </tr>\n");
write("<ul>\n<li>"+ mail["_source"] +"</li>\n<li>"+ mail["_subject"] +"</li>\n<li>"+ t +"</li>\n</ul>\n");
}
// write("</table>");
return 1;
}

337
world/net/place/master.c Normal file
View file

@ -0,0 +1,337 @@
// $Id: master.c,v 1.67 2008/01/05 12:42:17 lynx Exp $ // vim:syntax=lpc
//
// part of the PSYC multicast implementation strategy. accepts remote slave
// rooms to link into here. the point is to not have the traffic of every
// single user entering and leaving. if you like that, the automatic and
// transparent group/master and slave does the job for you. these two
// distribution systems co-exist and in fact together create a very
// scalable multicast solution without using the "IP Multicast" protocol.
//
#include <net.h>
#ifdef ORIGINAL_MASTERS
#include <status.h>
#include <driver.h>
#ifdef WE_PROBABLY_DONT_NEED_THIS
# include <url.h>
#endif
virtual inherit NET_PATH "place/storic";
private volatile mapping l;
private volatile int netppl;
qJunction() { return 0; }
isLink(source) {
P2(("isLink %O in %O: %O\n", source, l, l[source]))
return member(l, source);
}
histClear(a, b, source, vars) {
if (b < 50) return;
netmsg(ME, "_notice_place_history_cleared", "--", ([
"_amount_messages" : a ]) );
// invisible msg
return ::histClear(a, b, source, vars);
}
netsize() { return netppl+size(); }
save() {
if (l) {
vSet("links", l);
P2(("saving links: %O\n", v("links")))
}
return ::save();
}
reboot(reason, restart, pass) {
if (mappingp(l)) {
if (restart)
netmsg(ME, "_notice_unlink_shutdown_temporary",
"Server restart in progress. Connection to [_source] dismantled.",
([]));
else
netmsg(ME, "_notice_unlink_shutdown",
"Server shutdown in progress. Connection to [_source] dismantled.",
([]));
l = 0;
}
// would destruct junctions before slave::reboot() has been called?
// no.. because we no longer selfdestruct in reboot
return ::reboot(reason, restart, pass);
}
load(a) {
mixed rc;
rc = ::load(a);
unless(l) {
netppl=0;
#if 1
// die frage lautet: wollen wir das?
// ja, dann bleiben alle slaves up to date
// und sollte ein temporärer dabei sein, fliegt er hiermit raus
l = v("links");
if (mappingp(l)) {
P2(("reestablishing links: %O\n", l))
netmsg(ME, "_notice_unlink_restart_complete",
"Connection to [_source] reestablished.", ([]));
}
// wir lassen uns jeden link mit nem _request_link vom slave bestätigen
// also wird "l" nach gebrauch gelöscht!
#endif
l = ([]);
}
return rc;
}
static eachppl(link, size) { netppl += to_int(size); }
msg(source, mc, data, mapping vars) {
P2(("master:msg(%O, %O, %O, %O)\n", source, mc, data, vars))
if (stringp(source)) {
string relay;
int isli = member(l, source);
P2(("%O isli:%O source:%O links:%O\n", ME, isli, source, l))
#if 1 // is this stuff doing something useful?
if (!(qJunction() && stringp(vars["_source_relay"])
&& is_formal(vars["_source_relay"]))
&& isli && (relay = vars["_source_relay"])) {
//if (isli && (relay = vars["_source_relay"])) {
#if 0 //def WIR_TESTEN
P0(("%O: source %O (%O) und relay %O (%O) vertauscht\n", ME,
source, vars["_source"], relay, vars["_source_relay"]))
#else
P1(("%O: source %O und relay %O vertauscht\n", ME,
source, relay))
#endif
// one day we will have to take heed who has the
// privilege of linking us, as this is again a
// nice chance for spoofing.. but then again if someone
// dares to, he quickly ends up on the blacklist
// TODO: we need to check when exactly we need that
// or optimize on source == source_relay
// on link level
vars["_source_relay"] = source;
source = relay;
} else
#endif
switch(mc) {
// should also handle _request_enter i suppose
case "_request_link":
// when source is an ip number we could do a 10 second
// call_out and retry after resolving that ip number..
// or we expect all links to resolve at psyc negotiation
// time before getting here.. better solution..
unless(isli) {
// save();
//unless (qSilent()) // || v("quiet"))
monitor_report("_notice_link_report",
S("%O linked by %s (%O)", ME, source, l[source]));
// let ppl in room see what's happening..?
// this also goes out to all links, thus serves also as echo
// but this requires fiddling around on the linked slave whether its an
// controlmsg... so we simply send it separately
// reminds of _notice_place_enter* in place/basic
// could send identification here for junctions?
unless(v("_filter_presence"))
castmsg(source, "_notice_link_topic",
"Link to [_source] established. [_topic]",
([ "_topic" : (v("topic") || "") ]) );
sendmsg(source, "_notice_link",
"Link to [_source] established.", ([
"_topic" : v("topic") || "",
// "_filter_conversation" : v("_filter_conversation"),
"_filter_presence" : v("_filter_presence")
]));
} else {
P1(("%O link update: %s in %s\n", ME,l[source],source))
}
l[source] = vars["_amount_members"];
unless(isli) save();
// netppl=0; walk_mapping(l, "eachppl", ME);
return 1;
case "_error_rejected_message_membership":
// TODO: the place does not remember us...
// maybe it does not want to get our news.
// treat it like an unlink?
case "_request_unlink":
if (member (l, source)) {
P1(("%O unlinked by %s (%O)\n", ME,source,l[source]))
m_delete(l, source);
save();
sendmsg(source, "_notice_unlink",
"Link to [_source] dropped.");
} else
D(S("%O got unexpected unlink from %s (%O)\n",
ME, source, vars));
netppl=0; walk_mapping(l, "eachppl", ME);
return 1;
}
}
#ifdef WE_PROBABLY_DONT_NEED_THIS
if (stringp(source)) {
string host;
host = parse_uniform(source, 1)[UHost];
unless (chost(host)) {
dns_resolve(host,
(:
register_host($6, $1);
if ($1 != -1) {
::msg($2, $3, $4, $5);
debug_message(sprintf("MASTER: %O resolves to %O\n", $6, $1));
} else {
debug_message(sprintf("MASTER: %O does not resolve. ignoring. (closure).\n", $6));
}
return; :), source, mc, data, vars, host);
return;
} else if (chost(host) == -1) {
P1(("MASTER: %O does not resolve. ignoring.\n", host))
return;
}
}
#endif
return ::msg(source, mc, data, vars);
}
volatile string lastlink;
localmsg(source, mc, data, mapping vars) {
if (mappingp(vars)) {
m_delete(vars, "_amount_members");
m_delete(vars, "_amount_servers");
} else vars = ([]);
::castmsg(source, mc, data, vars);
}
#if 1
static eachlink(link, size, source, mc, data, vars) {
// we don't send to empty slaves..
// but for now we let them stay linked
// we could as well delete them.. hmm TODO
// and what about keeping history, topic and
// other control information in sync?
// okay.. it's not that simple
//unless (size) return;
unless (sendmsg(link, mc, data, vars, source)) {
// when send_udp fails, we get to know this at the *next* attempt
// to send a message. at least that's what the linux kernel seems to do
// most important thing, if it happens we need to resend the packet!
//P0(("%O: transmission damaged to %s (%O)\n", ME, link, size))
monitor_report("_failure_damaged_transmission", S("%O: transmission damaged to %s (%O)", ME, link, size));
unless (sendmsg(link, mc, data, vars, source)) {
D2( D("ERROR! resend failed a priori. this shouldn't happen.\n"); )
// if we got here, then we are probably not running linux
// let's assume this link is really broken and remove it
m_delete(l, link);
} else if (lastlink) {
// resend was successful, supposedly, or it didnt generate an immediate error
// so we can look into deleting the link that actually caused the problem
// on linux that's the one we sent something to *before*
if (l[lastlink]) {
l[lastlink] = 0; // give it one more try
} else {
P0(("transmission damaged to %s, removed probable cause of trouble: %s\n", link, lastlink))
m_delete(l, lastlink);
}
}
}
lastlink = link;
}
#endif
netmsg(source, mc, data, mapping vars) {
mapping myv;
#if 0 //def DRIVER_HAS_INLINE_CLOSURES
vars["_amount_members"] = netppl+size();
vars["_amount_servers"] = 1+sizeof(l);
walk_mapping(l, (: sendmsg($1, $3,$4,$5,$6) :),
mc,data,vars,source );
D("using closure\n");
#else
#ifdef QUIET_REMOTE_MEMBERS
if (abbrev("_notice_place_enter", mc)) return;
if (abbrev("_notice_place_leave", mc)) return;
#endif
myv = vars + ([
"_amount_members": netppl+size(),
"_amount_servers": 1+sizeof(l),
]);
lastlink = 0;
// here you can see some pre-foreach LPC code :)
walk_mapping(l, #'eachlink, source, mc, data, myv);
#endif
}
castmsg(source, mc, data, mapping vars) {
// TODO: psyc 1.1 / context oriented thingies will want to set
// context for the delivery to the slaves
// WHAT about junctions? will they set themselves as context
// aswell?
if (l) {
P2(("master:castmsg(%O,%O) w/_context %O and _nick_place %O\n",
source, mc, vars["_context"], vars["_nick_place"]))
// why is this necessary here again?
// and shouldn't it be the identification rather than ME?
vars["_context"] = ME;
// this one's even worse
vars["_nick_place"] = MYNICK;
netmsg(source, mc, data, vars);
}
localmsg(source, mc, data, vars);
}
memberInfo(person) {
if (netppl) {
unless (person) person = previous_object();
sendmsg(person, "_status_place_net_members_amount",
"[_nick_place] contains [_amount_members] people \
on [_amount_servers] servers.", ([
"_nick_place": MYNICK,
"_amount_members": netppl+size(),
"_amount_servers": 1+sizeof(l),
]) );
// return 0;
}
return ::memberInfo(person);
}
#if 0
showStatus(person, al, mc, data, vars) {
::showStatus(person, al, mc, data, vars);
if (l && al) walk_mapping(l, "eachstatus", ME, person);
return 1;
}
#else
cmd(a, args, b, source, vars) {
if (b) switch(a) {
case "links":
case "li":
if (sizeof(args) > 1) return 0;
if (l) walk_mapping(l, "eachstatus", ME, source);
return 1;
}
return ::cmd(a, args, b, source, vars);
}
#endif
static eachstatus(link, size, person) {
sendmsg(person, "_status_place_link_slave",
"Link [_link] has [_amount_members] members.",
([ "_link": link, "_amount_members": size ]) );
}
mixed isValidRelay(mixed x) { return x == ME || member(l, x); }
#else
# include "storic.c"
#endif

217
world/net/place/news.c Normal file
View file

@ -0,0 +1,217 @@
// $Id: news.c,v 1.99 2008/02/09 15:15:41 lynx Exp $ // vim:syntax=lpc
/*
* a place that polls an RSS / RDF xml page that
* contains "news" from sites like slashdot, heise.de, etc
* for a compilation of available RSS feeds take a look at
* http://www.webreference.com/services/news/
*
* technical information on RSS:
* http://docs.kde.org/en/3.1/kdenetwork/knewsticker/introduction.html#rssfiles
*
* TODO: check version tag and parse according to that
*
* Examples for qNewsfeed()
* "http://www.heise.de/newsticker/heise.rdf"
* "http://slashdot.org/slashdot.rss"
*
* Cool feeds:
* "http://www.webreference.com/services/news/index.html"
*/
#include <net.h>
#include <status.h>
#include <storage.h>
#include <xml.h>
#include <text.h> // NO_INHERIT, but virtual takes care of that
inherit NET_PATH "place/master";
inherit NET_PATH "xml/parse";
protected mapping _news; // ein wenig mehr ordnung im .o file
protected mapping known; // links of known news
volatile object feed;
volatile string prefix, modificationtime2;
handleNews(buffer);
// always show amount, never names.
makeMembers() { return ::makeMembers(1); }
publish(link, headline, channel) {
#if 1
// this is specific to shortnews.de who do a little privacy
// intrusion by tagging their rss feeds with personalized "u_id"
int uid = strstr(link, "&u_id");
if (uid != -1) link = link[0 .. uid-1];
#endif
PT(("%O publish %O\n", ME, link))
// this could move out into a NEWS_PUBLISH() for torrents
if (trail(".torrent", link))
castmsg(ME, "_notice_offered_file_torrent",
"([_nick_place]) [_file_title] [_uniform_torrent]",
([ "_file_title": headline,
"_uniform_torrent": link,
"_channel_title": channel ])
);
else castmsg(ME, "_notice_headline_news",
"([_nick_place]News) [_headline] [_page_news]",
([ "_headline": headline,
"_page_news": link,
"_channel": channel ])
);
}
connect() {
unless (feed) {
feed = qNewsfeed() -> load();
feed -> sAgent(SERVER_VERSION " builtin RSS to PSYC gateway - We'd prefer you to push your news in realtime instead of having us poll for it! See http://about.psyc.eu/Newscasting about that.");
feed->content(#'handleNews, 1);
} else {
feed->refetch(#'handleNews);
}
}
handleNews(buffer) {
// called when connection is closed
// put your logic here
int i;
mapping new, diff, items;
string href;
XMLNode item;
prefix = "";
// D2(D("strlen(buffer) = " + strlen(buffer) + "\n");)
if (intp(_news = xmlparse(buffer))) {
P0(("%O could not parse %O\n", ME, qNewsfeed()))
return;
}
unless(v("channel")) {
XMLNode c;
// net/place/news.c:67: (s)printf(): BUFF_SIZE overflowed...
// program: net/place/news.c, object: place/gmaps line 67
// _news is too big to debug this way! :(
P4(("%O got _news %O\n", ME, _news))
if (c = _news["/channel"]) {
vSet("channel", ([ "title" : c["/title"][Cdata],
"link" : c["/link"][Cdata],
"description" : c["/description"][Cdata] ]));
}
else {
P0(("%O cannot find channel data in %O\n", ME, qNewsfeed()))
return;
}
}
// compare and see if there is new data
new = ([ ]);
items = ([ ]);
unless(known) known = ([ ]);
P2(("known: %O\n", known))
foreach(item : (_news["/item"] || _news["/channel"]["/item"])) {
// breaks here sometimes, but then the RSS must be stupid
href = item["/link"][Cdata];
new[href] = 1;
items[href] = item;
}
foreach(href : new) {
unless(known[href]) {
string l = items[href]["/link"][Cdata];
string t = items[href]["/title"][Cdata];
if (strlen(l) > 5 && stringp(t))
publish(l, replace(t, "\n", " "), v("channel")["title"]);
else {
PT(("%O encountered funny link %O or title %O\n",
ME, l, t))
}
}
}
known = new;
save(); // to be discussed if we really need this
}
showStatus(verbosity, al, person, mc, data, vars) {
if (mappingp(_news) && verbosity & VERBOSITY_NEWSFEED && _news[prefix + "_title"])
sendmsg(person, "_status_place_description_news_rss",
"RSS Newsfeed for [_news_channel_title]: \"[_news_channel_description]\"\n"
"Available from [_link_news_rss]."
" Last check: [_time_fetch]. Last change: [_time_modification]", ([
"_news_channel_title" : v("channel")["_title"],
"_news_channel_description" : v("channel")["_description"],
"_time_modification" : feed->qHeader("modificationtime") || modificationtime2,
"_time_fetch" : feed->qHeader("_fetchtime"),
"_link_news_rss" : qNewsfeed()
]) );
return ::showStatus(verbosity, al, person, mc, data, vars);
}
// overrides mayLog in storic.c
mayLog(mc) {
return abbrev("_notice_headline", mc) ||
mc == "_notice_offered_file_torrent";
}
//#if 0
cmd(a, args, b, source, vars) {
switch (a) {
case "news":
connect();
return 1;
}
return ::cmd(a, args, b, source, vars);
}
//#endif
msg(source, mc, data, vars) {
// receive pings from blogs etc.
if (abbrev("_notice_update", mc)) {
// mixed *u;
//
// unless(vars["_location_feed"]) return;
// u = parse_uniform(vars["_location_feed"]);
if(qAllowExternal(source, mc, vars))
connect();
// would be better if the blog delivered the whole story
// then we wouldn't even need a "news" room for this
return;
}
return ::msg(source, mc, data, vars);
}
// new: receive and process http://www.xmlrpc.com/weblogsCom pings
//
// the bad news about pings: they contain 0 information other than
// some unspecified event happened.
// the good news about pings: they aren't worthy of parsing them
htpost(prot, query, headers, qs, data, noprocess) {
if (headers["content-type"] == "text/xml") {
string s, t;
// parses both unworthy trashy formats:
if (stringp(data)) sscanf(data, "%s>http://%s</%s", t, s, t);
htok(prot);
if (stringp(data) && strstr(data, "SOAP-ENV") != -1) {
//sscanf(data, "%s>http://%s</weblogurl>%s", t, s, t);
write(T("_XML_RPC_weblog_pong_SOAP", 0));
} else {
//sscanf(data, "%s<value>http://%s</value>%s", t, s, t);
write(T("_XML_RPC_weblog_pong", 0));
}
// now check the credentials and do the update
unless (same_host(query_ip_number(), qNewsfeed()->qHost())) {
P0(("%O got unsolicited XML from %O promoting %O\n",
ME, query_ip_name(), s || data))
return 1;
}
P0(("%O got XML from %O promoting %O\n",
ME, query_ip_name(), s || data))
connect();
// not disabling reset yet. TODO
return 1;
}
P0(("%O got htpost from %O containing %O\n", ME, query_ip_name(), data))
//return ::htpost(prot, query, headers, qs, data, noprocess);
}

18
world/net/place/owned.c Normal file
View file

@ -0,0 +1,18 @@
// $Id: owned.c,v 1.101 2007/09/08 21:25:20 lynx Exp $ // vim:syntax=lpc
//
// a room that has an owner and friends to help him
// traditional psycmuve set-up, just in case old place code uses it
// don't use this for new code
//
#define BASIC
#define PLACE_FILTERS
#define PLACE_HISTORY
#define PLACE_HISTORY_EXPORT
#define PLACE_SCRATCHPAD
#define PLACE_LOGGING
#define PLACE_OWNED
#define PLACE_STORE_COMMAND
#define PLACE_STYLE_COMMAND
#include "archetype.gen"

7
world/net/place/public.c Normal file
View file

@ -0,0 +1,7 @@
// $Id: public.c,v 1.30 2008/03/29 17:25:35 lynx Exp $ // vim:syntax=lpc
#include <net.h>
#define BASIC
#define PLACE_FILTERS
#define PLACE_LOGGING
#include "archetype.gen"

276
world/net/place/slave.c Normal file
View file

@ -0,0 +1,276 @@
// $Id: slave.c,v 1.64 2008/03/28 20:05:44 lynx Exp $ // vim:syntax=lpc
//
#define TIME_UPDATE_MINWAIT 33 // 33 seconds
#include <net.h>
#include <status.h>
virtual inherit NET_PATH "place/storic";
protected volatile string master, mastertrail;
protected volatile int members, servers;
private volatile int lastup;
histClear(a, b, source, vars) { if (b > 49) return ::histClear(a, b, source, vars); }
// the flag allows forced update and avoids call_out loops
#define UPDATE_NOW 0
#define UPDATE_SOON 1
#define UPDATE_REMINDER 2
qJunction() { return 0; }
update(flag) {
int t;
unless(master) return;
t = time() - lastup;
P2(("update(%O) - %O to go.\n", flag, TIME_UPDATE_MINWAIT - t))
if (flag == UPDATE_NOW || t > TIME_UPDATE_MINWAIT) {
lastup = time();
sendmsg(master, "_request_link", 0,
([ "_amount_members": to_string(size()) ]) );
} else if (flag == UPDATE_SOON)
call_out(#'update, TIME_UPDATE_MINWAIT+1-t, UPDATE_REMINDER);
}
void create() {
lastup = time(); // delay linkup by 7 seconds (see below)
::create();
}
#if 0
void reset(int again) {
if (again) update(UPDATE_SOON); // just in case..
else lastup = time(); // delay linkup by 7 seconds (see below)
return ::reset(again);
}
#endif
sIdentification(it) {
identification = it;
}
sMaster(link, modflag) {
unless (abbrev("psyc:", link))
link = "psyc://"+ link +"/"+ psycName();
mastertrail = master = lower_case(link); // lower_case UNI policy
identification = link;
set_context(ME, link);
// some kinda kludge until the psyc layer gives us the true UNI
// if (abbrev("psyc://ve.", master)) mastertrail = master[10..];
// P2(("mastertrail = %O\n", mastertrail))
//call_out(#'update, 7, UPDATE_NOW);
update(UPDATE_NOW);
}
mixed isValidRelay(mixed x) { return x == master || x == ME; }
msg(source, mc, data, vars) {
P2(("slave:msg(%O, %O, %O, %O)\n", source, mc, data, vars))
// if (vars["_context"]) return -1; // may not happen
// status update from master / identification
if (master && source == master ||
identification && source == identification) {
/* a message from our master / identification to us
* usually a status update or some other kind of control msg
* this control msg logic has moved around, but hasn't changed
*/
switch(mc) {
case "_notice_place_topic":
vSet("topic-user", vars["_nick"]);
// fall thru
case "_notice_place_topic_official":
vSet("topic", vars["_topic"]);
break;
case "_notice_place_topic_removed":
vSet("topic-user", vars["_nick"]);
break;
case "_notice_link_topic":
vSet("topic", vars["_topic"]);
// fall thru
case "_notice_link":
if (vars["_filter_presence"] &&
to_int(vars["_filter_presence"]) != 0)
vSet("_filter_presence", source);
else
vDel("_filter_presence");
//m_delete(vars, "_filter_presence");
break;
case "_notice_place_topic_removed_official":
vDel("topic");
break;
case "_error_necessary_link_place":
case "_error_rejected_message_membership":
// add protection from loops?
castmsg(ME, "_warning_place_link_lost",
"Master link [_master] has forgotten about us. Hold on.",
([ "_master" : master ]) );
// fall thru
case "_notice_unlink_restart":
case "_notice_unlink_restart_complete":
// update (UPDATE_NOW);
update (UPDATE_SOON);
return 1;
case "_notice_place_history_cleared":
::histClear(vars["_amount_messages"], 60, source, vars);
return 1;
case "_status_place_filter_presence":
if (vars["_filter_presence"] &&
to_int(vars["_filter_presence"]) != 0)
vSet("_filter_presence", source);
else
vDel("_filter_presence");
return 1;
}
if (abbrev("_notice_place_enter", mc)) {
// master notifies us that _source_relay was allowed
// to enter - kind of fake
string relay = vars["_source_relay"];
m_delete(vars, "_source_relay");
vars["_nick_place"] = MYNICK;
return ::msg(relay, mc, data, vars);
}
if (abbrev("_notice_place_leave", mc)) {
string relay = vars["_source_relay"];
m_delete(vars, "_source_relay");
vars["_nick_place"] = MYNICK;
return ::msg(relay, mc, data, vars);
}
return castmsg(source, mc, data, vars);
}
// someone is sending a message via us.
// we may send it to the master and if we dont return will pass
// it on to local msg()
// TODO: need to do some kind of checks if we want to forward
// sth for the sender
if ((!vars["_context"] // should not happen, but...
// things not to forward
&& !(abbrev("_request_leave", mc)
|| abbrev("_request_context_leave", mc))
// things we want to forward
||abbrev("_message", mc)
|| !v("_filter_presence") && (abbrev("_request_enter", mc)
|| abbrev("_request_context_enter", mc))
)
) { // source != master implied above
// we let upstream handle it
// TODO: we _must_ be linked to do this
// looks like a job for the notorious queue
//
// otherwise a slave may send an _request_enter to
// the master which is silent and should therefore
// drop the packet.
// and the user is left alone
// the master could catch such behaviour... but...
// complicates things and is more harmful than useful
//
// hrmpf. IMHO we should send it via master, if
// this does not work then debug it!
// hey, its lynX who told me to do that :)
#if 0
sendmsg(master, mc, data, vars + ([
"_location": query_ip_name(source),
"_source_relay": ME,
]), source);
#else
sendmsg(identification, mc, data, vars + ([
// what about peer scheme, host and -port
// ah, did just that in usercmd sayvars
"_location": objectp(source) ?
query_ip_name(source) : source,
"_source_relay": vars["_source_relay"] || source
]));
#endif
// if (abbrev("_message", mc)) return 1;
return 1;
#if 0 // wo war der Sinn von dem Code?
D3(else D(S("slave:msg from %O master %O, mastertrail %O\n",
source, master, mastertrail));)
if (source == master || (vars["_source"] == master &&
stringp(source) && trail(mastertrail, source))) {
string relay = vars["_source_relay"];
// if this were psyc 1.1, we wouldnt receive messages
// relayed, but have proper _context. i guess we want
// to implement both forms and maybe one day disallow
// one or the other on a per-room basis.
if (relay) {
// dieser teil war auskommentiert..
// was will mir das sagen? ich werde bugs auslösen?
// jopp
// vars["_source_relay"] = master;
// master could spoof local objects
// source = psyc_object(relay) || relay;
// geht das? hu?
vars["_source_relay"] = vars["_source"];
P2(("slave:msg(%O,%O,%O) relay=%O\n",
source, mc, data, relay))
}
}
#endif
}
// hm... can we simply do that?
return ::msg(source, mc, data, vars);
}
castmsg(source, mc, data, vars) {
P2(("slave:castmsg(%O, %O, %O, %O)\n",
source, mc, data, vars))
if (member(vars, "_amount_members")) {
members = to_int(vars["_amount_members"]);
m_delete(vars, "_amount_members");
}
if (member(vars, "_amount_servers")) {
servers = to_int(vars["_amount_servers"]);
m_delete(vars, "_amount_servers");
}
::castmsg(source, mc, data, vars);
}
enter(source,mc,data,vars) {
update (UPDATE_SOON);
return ::enter(source,mc,data,vars);
}
leave(source,mc,data,vars) {
update (UPDATE_SOON);
return ::leave(source,mc,data,vars);
}
memberInfo(person) {
unless (members && servers) return ::memberInfo(person);
unless (person) person = previous_object();
sendmsg(person, "_status_place_net_members_amount",
"[_nick_place] contains [_amount_members] people \
on [_amount_servers] servers.", ([
"_nick_place": MYNICK,
"_amount_members": members,
"_amount_servers": servers,
]) );
return 0;
}
showStatus(verbosity, al, source, mc, data, vars) {
if (members && master) {
sendmsg(source, "_status_place_link",
"Network link to [_link] active.",
([ "_link": master ]) );
}
return ::showStatus(verbosity, al, source, mc, data, vars);
}
qAllowExternal(source, mc) {
if (source == master) return 1;
}
reboot(reason, restart, pass) {
if (master) {
sendmsg(master, "_request_unlink");
master = 0;
}
return ::reboot(reason, restart, pass);
}

View file

@ -0,0 +1,14 @@
// $Id: standard.c,v 1.52 2007/09/08 21:25:20 lynx Exp $ // vim:syntax=lpc
//
// the room that used to get cloned when there is no specific program available.
// it has no owners and it is private by default.
//
// this is no longer the default place code. it is kept here in case you
// need to go back to the old style. don't inherit this.
#define BASIC
#define PLACE_MASQUERADE
#define PLACE_MASQUERADE_COMMAND
#define PLACE_PUBLIC_COMMAND
//#define PLACE_STORE_COMMAND
#include "archetype.gen"

16
world/net/place/storic.c Normal file
View file

@ -0,0 +1,16 @@
// $Id: storic.c,v 1.102 2007/09/08 21:25:20 lynx Exp $ // vim:syntax=lpc
//
// dont ask what "storic" is supposed to mean..
// it's a room object that keeps a lastlog, a history of the last messages
//
// this is the old storic implementation, used in inheritance chains.
// some old code may need it, but don't write new code on top of this.
#define BASIC
#define PLACE_FILTERS
#define PLACE_HISTORY
#define PLACE_HISTORY_EXPORT
#define PLACE_LOGGING
#define PLACE_STORE_COMMAND
#include "archetype.gen"

580
world/net/place/threads.c Normal file
View file

@ -0,0 +1,580 @@
// $Id: threads.c,v 1.41 2008/01/05 12:42:17 lynx Exp $ // vim:syntax=lpc
//
#include <net.h>
#include <person.h>
#include <status.h>
inherit NET_PATH "place/owned";
#ifndef DEFAULT_BACKLOG
# define DEFAULT_BACKLOG 5
#endif
// datenstruktur für threads?
//
// bestehende struktur ist: großes array von entries.
//
// wie wärs mit mapping mit key=threadname und value=array-of-entries
// subjects werden abgeschafft: sie sind der name des threads
// wer einen thread in seinem reply umnennen will legt in wirklichkeit
// einen neuen thread an, meinetwegen mit "was: old thread"
//
// der nachteil an solch einer struktur wäre, dass man neue comments
// in alten threads nicht so schnell findet - man ist auf die notification
// angewiesen, was andererseits die stärke von psycblogs ist.
// man könnte die notifications zudem noch in die history einspeisen..
//
// nachteile an der bestehenden struktur ist: 1. threadname in jeder
// entry, 2. threads nur mittels durchlauf des ganzen blogs darstellbar
//
// momentmal.. das was du "comments" nennst sind doch schon die threads!
protected mapping* _thread;
volatile int last_modified;
volatile string webact;
create() {
::create();
unless (pointerp(_thread)) _thread = ({ });
}
cmd(a, args, b, source, vars) {
// TODO: multiline-sachen irgendwie
mapping entry;
int i = 0;
int num_entries;
//unless (source) source = previous_object();
switch (a) {
case "entries":
num_entries = sizeof(args) >= 2 ? to_int(args[1]) : DEFAULT_BACKLOG;
// _thread[<5..]
foreach( entry : _thread[<num_entries..] ) {
sendmsg(source, "_list_thread_item",
// hier auch noch den text?
"([_number]) \"[_thread]\", [_author]",
([
"_thread" : entry["thread"],
"_text" : entry["text"],
"_author" : entry["author"],
"_date" : entry["date"],
"_number" : i++,
"_nick_place" : MYNICK ]) );
}
return 1;
case "thread":
unless (sizeof(args) > 2){ // num + thread
sendmsg(source, "_warning_usage_thread",
"Usage: /thread <threadid> <title>", ([ ]));
return 1;
}
return setSubject(to_int(args[1]), ARGS(2));
case "blog":
case "submit":
case "addentry":
unless (qAide(SNICKER)) return;
unless (sizeof(args) >= 2) {
sendmsg(source, "_warning_usage_submit",
"Usage: /submit <title> <text>", ([ ]));
return 1;
}
return addEntry(ARGS(2), SNICKER, args[1]);
// TODO: append fuer multiline-sachen
#if 0
case "iterator":
unless (qAide(SNICKER)) return;
sendmsg(source, "_notice_thread_iterator",
"[_iterator] blog entries have been requested "
"since creation.", ([
// i suppose this wasn't intentionally using
// MMP _count so i rename it to _iterator
"_iterator" : v("iterator")
]) );
return 1;
#endif
case "deblog":
case "delentry":
unless (qAide(SNICKER)) return;
// ist das ein typecheck ob args ein int is?
if (sizeof(regexp( ({ args[1] }) , "^[0-9][0-9]*$"))) {
unless (delEntry(to_int(args[1]), source, vars)) {
sendmsg(source,"_error_invalid_thread_item",
"There is no such thread item.", ([ ]));
} else {
sendmsg(source, "_notice_thread_item_removed",
"Thread item [_number] has been removed.",
([ "_number" : ARGS(1) ]) );
}
}
return 1;
}
return ::cmd(a, args, b, source, vars);
}
msg(source, mc, data, mapping vars){
P2(("blog.c's msg: mc %O, source %O\n", mc, source))
// TODO: die source muss hierbei uebereinstimmen mit dem autor
if (abbrev("_notice_authentication", mc)){
sendmsg(source, "_notice_place_blog_authentication_success", "([_entry]) has been authenticated",
([ "_entry" : "1" ]) );
return;
}
if (abbrev("error_invalid_authentication", mc)) {
sendmsg(source, "_notice_place_blog_authentication_failure", "Warning, someone pretends to blog as you", ([ ]) );
return;
}
return ::msg(source, mc, data, vars);
}
#if 0
listLastEntries(number) {
mapping* entries;
int i;
entries = _thread || ({ });
unless (sizeof(entries)) return 1;
i = v("iterator") || 0;
vSet("iterator", i + 1);
return entries[<number..];
}
#endif
#if 0
allEntries(source) {
mapping* entries;
mapping ar;
int i = 0;
entries = _thread || ({ });
unless (sizeof(entries)) return 1;
foreach (ar : entries) {
sendmsg(source, "_message_", "([_number]) \"[_topic]\", [_author]", ([ // ??
"_topic" : ar["topic"],
"_text" : ar["text"],
"_author" : ar["author"],
"_date" : ar["date"],
"_number" : i++,
"_nick_place" : MYNICK ]) );
}
return 1;
}
#endif
#if 0
addForum() {
// suggested protocol message for the buha forum
// (creation of a new thread)
:_target psyc://psyced.org/@buha
:_encoding utf-8
:_nick_forum morpheus
:_category Test-Forum
:_thread Test-Thread_
:_page_thread https://www.buha.info/board/showthread.php?t=1
_notice_thread
[_nick_forum] hat einen neuen Thread in [_category] erstellt: [_thread] ([_page_thread])
.
}
#endif
setSubject(num, thread) {
mapping* entries;
entries = _thread || ({ });
// TODO: das hier muss sicherer
entries[num]["thread"] = thread;
_thread = entries;
save();
return 1;
}
// TODO: topic uebergeben
addEntry(text, unick, thread) {
mapping* entries;
mapping newentry = ([ "text" : text,
"author" : unick,
"date" : isotime(ctime(), 1),
"thread" : thread || "",
]);
entries = _thread || ({ });
entries += ({ newentry });
_thread = entries;
save();
castmsg(ME, "_notice_thread_item",
"[_nick] adds an entry in \"[_thread]\" of [_nick_place].", ([
"_entry" : text,
"_thread" : thread,
"_nick" : unick,
]) );
return 1;
}
addComment(text, unick, entry_id) {
mapping entry;
if (sizeof(_thread) > entry_id) {
entry = _thread[entry_id];
unless (entry["comments"]) {
entry["comments"] = ({ });
}
entry["comments"] += ({ (["text" : text, "nick" : unick ]) });
// vSet("entries", entries);
castmsg(ME, "_notice_thread_comment",
"[_nick] adds a comment in \"[_thread]\" of [_nick_place].", ([
"_entry" : entry["text"],
"_thread" : entry["thread"],
"_comment" : text,
"_nick" : unick,
]) );
return save();
}
return -1;
}
delEntry(int number, source, vars) {
array(string) entries, authors, a;
string unick;
int size;
entries = _thread || ({ });
unless (size = sizeof(entries)) return 0;
if (number >= size) return 0;
if (qAide(unick = lower_case(SNICKER))) {
unless (lower_case(entries[number]["author"]) == unick) return 0;
}
_thread = entries[0..number-1] + entries[number+1..];
save();
return 1;
}
htget(prot, query, headers, qs, data) {
mapping entrymap;
mixed target;
string nick;
int i;
int a;
mapping* entries;
int num_entries = query["last"] ? to_int(query["last"]) : DEFAULT_BACKLOG;
unless (webact) webact = PLACE_PATH + MYLOWERNICK;
// shouldnt it be "html" here?
sTextPath(query["layout"] || MYNICK, query["lang"], "ht");
// Kommentare anzeigen
if (query["comments"]) {
htok(prot);
// kommentare + urspruengliche Nachricht anzeigen
displayHeader();
displayComments(_thread[to_int(query["comments"])]);
// eingabeformular ohne betreff
write("<form action='" + webact + "' method='GET'>\n"
"<input type='hidden' name='request' value='post'>\n"
"PSYC Uni: <input type='text' name='uni'><br>\n"
"<input type='hidden' name='reply' value='" + query["comments"] +"'>\n"
"<textarea name='text' rows='14' cols='80'>Enter your text here</textarea><br>\n"
"<input type='submit' value='submit'>\n"
"</form>\n");
write("<br><hr><br>");
logView(a < 24 ? a : 12, "html", 15);
displayFooter();
return 1;
}
// formularbehandlung
if (query["request"] == "post" && query["uni"]) {
htok(prot);
/*
sendmsg uni -> _request_authentication mit thread und text drin
dann auf die antwort warten die nen vars mapping mit thread + text hat wieder
*/
if (nick = legal_name(target = query["uni"])) {
target = summon_person(nick);
nick = target->qNick();
} else {
nick = target;
// write("Hello " + query["uni"] + "<br>\n");
// write("Remote auth doesn't work yet. TODO!!!\n");
// return 1;
}
#ifdef OWNED
if (qAide(nick)) {
#endif
#if 0
sendmsg(target, "_request_authentication", "please auth me!",
(["_host_IP" : query_ip_number(),
"_blog_thread" : query["thread"],
"_blog_text" : query["text"] ]));
write("your submit is avaiting authentication by " + query["uni"] + "<br>\n");
#endif // 0
if (target->checkAuthentication(ME, ([ "_host_IP" : query_ip_number() ]) ) > 0) {
// check ob reply auf irgendwas ist...
if (query["reply"]) {
addComment(query["text"], query["uni"], to_int(query["reply"]));
} else {
addEntry(query["text"], query["uni"], query["thread"]);
}
write("authentication successful!\n");
} else {
write("not authenticated!\n");
}
#ifdef OWNED
} else {
write("You are not owner or aide of this place.\n");
}
#endif
return 1;
}
// neuen Eintrag verfassen
if (query["request"] == "form") {
htok(prot);
displayHeader();
write("<form action='" + webact + "' method='GET'>\n"
"<input type='hidden' name='request' value='post'>\n"
"PSYC Identity:<br><input type='text' name='uni' size=60><br>\n"
"Thread:<br><input type='text' name='thread' size=60><br>\n"
"Text:<br>\n<textarea name='text' rows='14' cols='64'></textarea><br>\n"
"<input type='submit' value='CREATE MESSAGE'>\n"
"</form>\n");
displayFooter();
return 1;
}
::htget(prot, query, headers, qs, data, 1); // no processing, just info
// javascript-export
if (query["export"] == "javascript") {
// check If-Modified-Since header
htok3(prot, "application/x-javascript", "Cache-Control: no-cache\n");
jscriptExport(num_entries);
} else if (query["export"] == "rss" || query["export"] == "rdf") {
// export als RSS
// scheinbar gibt es ein limit von 15 items / channel
// htquote auch hier anwenden
// check If-Modified-Since header
htok3(prot, "text/xml", "");
rssExport(num_entries);
} else {
// normaler Export
P2(("all entries: %O\n", _thread))
htok3(prot, "text/html", "Cache-Control: no-cache\n");
displayHeader();
// display the blog
displayMain(num_entries);
// display the chatlog
logView(a < 24 ? a : 12, "html", 15);
displayFooter();
}
return 1;
}
rssExport(last) {
int i;
int len;
len = sizeof(_thread);
if (last > len) last = len;
write("<?xml version=\"1.0\" encoding=\"" SYSTEM_CHARSET "\" ?>\n"
"<rdf:RDF\n"
"xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n"
"xmlns=\"http://purl.org/rss/1.0/\">\n\n"
"<channel>\n"
"\t<title>PSYC - Protocol for Synchronous Conferencing</title>\n"
"\t<link>http://www.psyc.eu</link>\n"
"\t<description>News about the PSYC project</description>\n"
"</channel>\n");
for (i = len - last; i < len; i++) {
write("\n<item>\n"
"\t<title>"+ _thread[i]["thread"] +"</title>\n"
"\t<link>http://" + SERVER_HOST + ":33333" + webact + "?comments=" + i + "</link>\n"
"\t<description>" + _thread[i]["text"] + "</description>\n"
"\t<dc:date>" + _thread[i]["date"] + "</dc:date>\n"
"\t<dc:creator>" + _thread[i]["author"] + "</dc:creator>\n");
write("</item>\n");
}
write("</rdf:RDF>\n");
}
jscriptExport(last) {
mapping item;
string buf = "";
// htok3(prot, "application/x-javascript", "Cache-Control: no-cache\n");
write("function Entry(thread, author, date, text) {\n"
"\tthis.thread = thread;\n"
"\tthis.author = author;\n"
"\tthis.date = date;\n"
"\tthis.text = text;\n"
"}\n\n"
"document.blogentries = new Array(\n");
foreach (item : _thread[<last..]) {
buf += "new Entry(\"" + item["thread"] + "\", \""
+ item["author"] + "\", \""
+ item["date"] + "\", \""
+ item["text"] + "\"),\n";
}
buf = buf[..<3] + ");";
write(buf);
}
#if 0
displayMain(last) {
int i;
int len;
len = sizeof(_thread);
if (last > len) last = len;
P2(("len %d, last %d\n", len, last))
for (i = len - last; i < len; i++) {
write("<table><tr><td class='blogthread'>" + _thread[i]["thread"]
+ "</td>"
"<td class='blogauthor'>" + _thread[i]["author"] + "</td>"
"<td class='blogdate'>" + _thread[i]["date"] + "</td></tr>"
"<tr><td class='blogtext' colspan=3>" + _thread[i]["text"]
+ "</td></tr>"
"<tr><td colspan=3 align='right'>");
write("<a href='" + webact + "?comments=" + i + "'>there are " + sizeof(_thread[i]["comments"]) + " comments</a>");
write("</td></tr></table>\n");
}
}
#endif
displayMain(last) {
int i;
int len;
string t;
len = sizeof(_thread);
if (last > len) last = len;
// reverse order
for (i = len-1; i >= len - last; i--) {
t = htquote(_thread[i]["text"]);
t = replace(t, "\n", "<br>\n");
write("<table class='newsTable' width='560px'>\n"
"<tr>"
"<td class='newsAuthor' width='20%'>" + _thread[i]["author"] + "</td>"
"<td class='newsTime' nowrap width='20%'>" + _thread[i]["date"] + "</td>"
"<td class='newsSubject' width='60%'>" + htquote(_thread[i]["thread"]) + "</td>"
"</tr>\n"
"<tr>"
"<td colspan='3' class='newsText'>" + t + "</td>"
"</tr>\n"
"<tr>"
"<td colspan='3' class='newsLink'><a href='" + webact + "?comments"
"=" + i + "'>" + sizeof(_thread[i]["comments"]) + " comments</a></td>"
"</tr>\n"
"</table>\n");
}
}
displayComments(data) {
mapping item;
write("Ursprüngliche Nachricht:<br>"
"<b>" + data["author"] + "</b>: " + data["text"] + "<br><br>\n");
if (data["comments"]) {
foreach(item : data["comments"]) {
write("<b>" + item["nick"] + "</b>: " + item["text"] + "<br>\n");
}
} else {
write("no comments...<br>\n");
}
}
nntpget(cmd, args) {
mapping item;
int i;
P2(("calling nntpget %s with %O\n", cmd, args))
switch(cmd) {
case "LIST":
write(MYNICK + " 0 1 n\n");
break;
case "ARTICLE":
i = to_int(args) - 1;
P2(("i is: %d\n", i))
P2(("entries: %O\n", _thread))
item = _thread[i];
write(S("220 %d <%s%d@%s> article\n",
i + 1, MYNICK, i + 1, SERVER_HOST));
write(S("From: %s\n", item["author"]));
write(S("Newsgroups: %s\n", MYNICK));
write(S("Subject: %s\n", item["thread"]));
write(S("Date: %s\n", item["date"]));
write(S("Xref: %s %s:%d\n", SERVER_HOST, MYNICK, i + 1));
write(S("Message-ID: <%s$%d@%s>\n", MYNICK, i+1, SERVER_HOST));
write("\n");
write(item["text"]);
write("\n.\n");
break;
case "GROUP":
write(S("211 %d 1 %d %s\n", sizeof(_thread),
sizeof(_thread), MYNICK));
break;
case "XOVER":
for (i = 0; i < sizeof(_thread); i++) {
item = _thread[i];
P2(("item: %O\n", item))
write(S("%d\t%s\t%s\t%s <%s%d@%s>\t1609\t22\tXref: news.t-online.com\t%s:%d\n",
i+1, item["thread"],
item["author"], item["date"],
MYNICK, i+1,
SERVER_HOST, MYNICK, i+1));
}
break;
default:
P2(("unimplemented nntp command: %s\n", cmd))
}
}
#ifndef STYLESHEET
# define STYLESHEET (v("_uniform_style") || "http://www.psyc.eu/blog.css")
#endif
// wir können zwei strategien fahren.. die technisch einfachere ist es
// die reihenfolge der elemente festzulegen und für jedes ein w(_HTML_xy
// auszuspucken. flexibler wär's stattdessen wenn jede seite ein einziges
// w(_PAGES_xy ausgeben würde in dem es per [_HTML_list_threads] oder
// ähnlichem die blog-elemente per psyctext-vars übergibt ... dann kann
// es immernoch per {_HTML_head_threads} header und footer einheitlich
// halten. womöglich kann man auch nachträglich plan A in plan B
// umwandeln..... hmmm -lynX
//
displayHeader() {
w("_HTML_head_threads",
"<link rel='stylesheet' type='text/css' href='"+
STYLESHEET +"'>\n"+
"<style type='text/css'>\n"
"<!--\n"
"body { font-family: lucida,verdana,geneva; }\n"
"td { font-family: lucida,verdana,geneva; }\n"
"table.newsTable {border: 1px solid #6f6; padding:4px; margin:6px;}\n"
"table td.newsAuthor {color:#fff; font-weight:bold;"
" border: 1px solid #6f6;"
" background-color:#041;}\n"
"table td.newsTime {color:#ddd;border: 1px solid #6f6;"
" background-color:#030;}\n"
"table td.newsSubject {color:#ddd; border: 1px solid #6f6;"
" background-color:#030;}\n"
"table td.newsLink {background-color:#030;}\n"
"table td.newsText {}\n"
"//-->\n"
"</style>\n"
"<body bgcolor='#002200' text='#33ff33' link='#ffdf00'"
"vlink='#ffaf00' alink='#00ff00'>\n\n");
}
displayFooter() {
w("_HTML_tail_threads", "</body>");
}