Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/obj/mpa.c b/obj/mpa.c
new file mode 100644
index 0000000..7bd1972
--- /dev/null
+++ b/obj/mpa.c
@@ -0,0 +1,1573 @@
+/* Das Servicepaket der Morgengrauen-Presseagentur. Eine erweiterte Zeitung.
+ Teilweise zur alten Zeitung identisch.
+
+ unter Verwendung der Zeitung von Jof, voellig umgeschrieben.
+
+ (C) Nov 1993 - 1996 Loco@Morgengrauen
+
+ Verwendung ausserhalb von Morgengrauen ist gestattet unter folgenden
+ Bedingungen:
+ - Benutzung erfolgt auf eigene Gefahr. Jegliche Verantwortung wird
+ abgelehnt. Bugs ausserhalb von MG sind nicht mein Problem.
+ - Auch in veraenderten oder abgeleiteten Objekten muss ein Hinweis auf
+ die Herkunft erhalten bleiben.
+ - Bitte fragt mich vorher!
+ Ein Update-Service besteht nicht. Ruecknahme dieser Lizenz ist jederzeit
+ moeglich. Und wer nicht in der Lage ist, neue Versionen selber anzupassen,
+ hat in der Administration eines Muds nichts zu suchen.
+
+
+ 04.11.93 Erste brauchbare Version
+ (... seitdem viele Aenderungen ...)
+ 13.09.95 ca 02:00 erwarte mpa
+ 13.09.95 ca 23:00 RebuildGroupList()
+ 15.09.95 vorlaeufig ausgebaut
+ 16.09. anders wieder eingebaut, und Kleinigkeiten
+ 05.12.95 ca 19:20 Spieler koennen nur noch eigene Artikel loeschen/verl.
+ 07.12.95 ca 23:00 Keine Anzeige der Statuszeile. Statuszeilen beginnen
+ mit ~#!, sind damit nicht mit dem Editor erzeugbar.
+ 20.12.95 ca 17:00 uebergehe thread/antworten
+ 31.01.96 wiederhole/uncatchup
+ 22.04.96 Aufraeumen ignorierter threads. ALPHA!
+ 24.04.96 + - . als Adressierungen, zeitungsmeldung
+ 02.10.96 Kleinigkeiten
+ 08.10.96 Kleinigkeiten
+ 05.12.96 antworte auf artikel <nr>, reply <neuer titel>,
+ versende artikel, Abkuerzungen fuer Rubrikennamen,
+ Layoutaenderungen,
+ Herkunft bei verlegten Artikeln in Statuszeile
+
+ Letzte Aenderung:
+ 04.11.06 Zesstra Anpassung an das neue Verhalten von inherit_list() in LD
+
+*/
+
+#include <properties.h>
+#include <language.h>
+#include <news.h>
+#include <wizlevels.h>
+#include <ansi.h>
+#include <input_to.h>
+#include "/mail/post.h"
+
+inherit "/std/thing";
+inherit NEDIT;
+/*
+#define DEBUG(x) if (funcall(symbol_function('find_player),"zesstra"))\
+ tell_object(funcall(symbol_function('find_player),"zesstra"),\
+ "MPA: "+x+"\n")
+#define DEBUGVAR(x) DEBUG(sprintf(x+":\n%O\n",x))
+*/
+#define DEBUGVAR(x)
+
+// Konfiguration, ggf mudabhaengig
+#define DEFAULTGROUP "allgemeines"
+#define MINIHELPPAGE "p/service/loco/doc/mini-mpa.txt"
+#define HELPPAGE "/p/service/loco/doc/mpa"
+#define WIZHELPPAGE "/p/service/loco/doc/mpa.wiz"
+#define SAVEMSGPATH(pl) ("/open/News/"+(geteuid(pl))+".news")
+#define IS_POST(r) (member(inherit_list(r),STDPOST+".c")>=0)
+#define INITIAL_SUBSCRIPTIONS \
+ ({ "bekanntmachungen", \
+ "d.ebene", \
+ "d.wueste", \
+ "d.inseln", \
+ "d.unterwelt", \
+ "d.dschungel", \
+ "d.gebirge", \
+ "d.polar", \
+ "d.wald", \
+ "d.fernwest", \
+ "d.vland", \
+ "d.anfaenger", \
+ "entwicklung", \
+ })
+
+// Makros etc.
+
+#define TP this_player()
+#define TI this_interactive()
+#define STATUSESCAPE "~#!"
+#define IS_STATUSLINE(s) ((s[0..1]=="#!")||(s[0..2]=="~#!"))
+//#define IS_STATUSLINE(s) (s[0..2]=="~#!")
+// in Rubrik muell fanden sich tatsaechlich noch solche uralten notes...
+#define IGNOREGROUP "*ignored*"
+#define NNADWMSG "*NNADWMSG*"
+#define SYSTEMGROUPS ({IGNOREGROUP,NNADWMSG})
+
+// Aufbau der ignoregroup:
+// ([group1:([tid1:lasttime1,tid2:lasttime2,...]),group2:...])
+
+// Flags fuer Message2string()
+#define M2S_VT100 1
+#define M2S_ANSI M2S_VT100
+#define M2S_REMOTE 2
+
+// Format von lasttitle
+#define LAST_TITLE 0
+#define LAST_WRITER 1
+#define LAST_TIME 2
+#define LAST_TID 3
+#define LAST_GROUP 4
+#define LAST_NR 5
+#define LAST_SIZEOF 6
+
+
+mapping read_until;
+mixed lasttitle; // Aufbau s.o.
+mixed message;
+int deadTID;
+string GROUP;
+
+int GetTID(mixed message);
+private void InitialSubscriptions();
+
+create()
+{
+ ::create();
+ seteuid(getuid());
+ GROUP="bekanntmachungen";
+ SetProp(P_SHORT,"Die Zeitung");
+ SetProp(P_NAME,"Zeitung");
+ SetProp(P_WEIGHT, 50);
+ SetProp(P_SIZE, 35);
+ SetProp(P_MATERIAL, ([MAT_PAPER: 100]) );
+ SetProp(P_GENDER, FEMALE);
+ AddId(({"nn","zeitung","servicepaket","mpa"}));
+ SetProp(P_NODROP,
+ "Das persoenliche Servicepaket der MPA kann man nicht wegwerfen.\n");
+ SetProp(P_NEVERDROP, 1);
+
+ if (!read_until) read_until=(["muell":-1]);
+}
+
+static mixed _query_read_msg() { return long(); }
+
+long() {
+ return "\
+Dies ist das Servicepaket der MPA (Morgengrauens Presse Agentur) -\n\
+die Zeitung des Morgengrauens.\n\
+Du kannst damit aktuelle Artikel lesen und schreiben, mit folgenden Befehlen:\n\
+ 'nn [rubrik]' (Neueste Nachrichten) wuehlt die Rubrik durch und schaut,\n\
+ ob was neu ist. Der erste ungelesene Artikel wird angezeigt.\n\
+ Ohne Argument werden alle Rubriken durchwuehlt.\n\
+ 'hilfe mpa' Ausfuehrliche Hilfsseite. Lesen dringend empfohlen!\n\
+Weitere Befehle:\n\
+ rubriken [neu] bestelle <rubrik> ab\n\
+ [lies ]rubrik <rubrik> abonniere <rubrik>\n\
+ inhalt [<rubrik>|neu|suche <text>] wiederhole ...\n\
+ nn <rubriken>|<liste> uebergehe ...\n\
+ [lies ]artikel <nummer>"+
+ ( (IS_LEARNER(TP)) ? " speichere artikel <nr>" : "" )+"\n\
+ schreib <titel> versende artikel [nr] an <adresse>\n\
+ antworte [auf artikel <nr>] [titel] verlege artikel <nr> nach <rubrik>\n\
+ loesche artikel <nr> zeitungsmeldung [neue Meldung]\n\
+ verbrenne zeitung wenn Dir alles zuviel wird....\n\
+"+ (IS_SEER(TP) ? "\
+Mit 'mail' bzw 'mail <spieler>' kannst Du Post lesen und schreiben.\n\
+" : "" )+"\
+Eingebaute aliase: note, catchup, reply, unsubscribe, subscribe, uncatchup.\n\
+Viele Befehle geben mit '<befehl> ?' einige Syntaxhinweise.\n\
+Aktuelle Rubrik: "+GROUP+"\n\
+";
+}
+
+
+init()
+{
+ ::init();
+
+ add_action("schreib","schreib");
+ add_action("schreib","schreibe");
+ add_action("schreib","note");
+ add_action("LiesArtikel","lies");
+ add_action("artikel","artikel");
+ add_action("loesche","loesch");
+ add_action("loesche","loesche");
+ add_action("rubrik","rubrik");
+ add_action("inhalt","inhalt");
+ add_action("rubriken","rubriken");
+ add_action("ReadNextUnread","nn");
+ add_action("Catchup","catchup");
+ add_action("Catchup","uebergeh");
+ add_action("Catchup","uebergehe");
+ add_action("Uncatchup","wiederhol");
+ add_action("Uncatchup","wiederhole");
+ add_action("Uncatchup","uncatchup");
+ add_action("Reply","antwort");
+ add_action("Reply","antworte");
+ add_action("Reply2","reply");
+ add_action("HelpPage","hilfe");
+ add_action("HelpPage","man");
+ add_action("Unsubscribe","unsubscribe");
+ add_action("Bestelle","bestell");
+ add_action("Bestelle","bestelle");
+ add_action("Subscribe","subscribe");
+ add_action("Subscribe","abonnier");
+ add_action("Subscribe","abonniere");
+ add_action("MoveMessage","verleg");
+ add_action("MoveMessage","verlege");
+ add_action("SetNNADWMSG","zeitungsmeldung");
+ add_action("Ignore","ignorier");
+ add_action("Ignore","ignoriere");
+ add_action("MailMessage","versende");
+ add_action("verbrennen","verbrenne");
+
+ if (IS_SEER(TP)) {
+ add_action("Mail","mail");
+ }
+ if (IS_LEARNER(TP)) {
+ add_action("SaveMessage","speicher");
+ add_action("SaveMessage","speichere");
+ add_action("ReadNextUnread","read"); /* NF Compatibility Special */
+ }
+ if (IS_ELDER(TP))
+ {
+ add_action("MoveTrash","trash");
+ }
+ init_rescue();
+}
+
+verbrennen(str) {
+ if (!str || !id(str)) return 0;
+ write("Du verbrennst Deine Zeitung mit groesstem Vergnuegen.\n");
+ say(TP->Name(WER)+" verbrennt "+
+ TP->QueryPossPronoun(FEMALE, WEN, SINGULAR)+" Zeitung in einem "
+ "Freudenfeuer.\n");
+ remove(1);
+ return 1;
+}
+
+// KillGroup - loescht eine nicht mehr benoetigte Rubrik aus der Liste.
+// Aufruf aus rubriken() und ReadNextUnread(), wenn die gueltige
+// Rubrikenliste sowieso schon abgerufen wurde.
+
+static KillGroup(name) { read_until=m_copy_delete(read_until,name); }
+
+/* RebuildGroupList() - tut doch nicht so, weil /secure/news anders arbeitet.
+ * Bleibt vorerst zum Nachschlagen.
+static RegisterGroup(name) { read_until[name]=1; }
+static RebuildGroupList() {
+ mixed groups;
+ if ((pointerp(groups=NEWSSERVER->GetGroups()))&&(sizeof(groups))) {
+ map(m_indices(read_until)-groups-SYSTEMGROUPS,#'KillGroup);
+ map(groups-m_indices(read_until),#'RegisterGroup);
+ }
+ TP->SetProp(P_READ_NEWS,read_until);
+}
+*/
+
+
+_set_autoloadobj(mixed arg) {
+
+ if (pointerp(arg) && sizeof(arg)>=2)
+ {
+ read_until=arg[1];
+ }
+ else {
+ if (TP)
+ read_until=((TP->QueryProp(P_READ_NEWS))||([]));
+ }
+
+ if (TP) TP->SetProp(P_READ_NEWS,read_until);
+}
+
+_query_autoloadobj() {
+ return 1;
+}
+
+static Mail(str) {
+ object mailer;
+ if (this_interactive()!=this_player()) return 0;
+ mailer=clone_object(MAILER);
+ mailer->SetOfficeName("mpa Kurierdienst");
+ mailer->do_mail( ((!str)||(str=="mail")) ? 0 : TP->_unparsed_args() );
+ return 1;
+}
+
+static varargs string Message2string(mixed msg,mixed messages,int flag,string group) {
+ // Aufrufe: (Nummer,Notes[,flag[,group]]) oder (Note,Notes[,flag[,group]])
+ // flag: M2S_VT100 : ggf ANSI-Codes verwenden
+ // M2S_REMOTE: Rubrik und Artikelnummer ausgeben (speichern, versenden)
+ // Achtung: Wenn flag&M2S_REMOTE, muss msg int sein
+ // group: Name der Rubrik, wenn nicht aktuelle Rubrik. Nur bei M2S_REMOTE
+
+ string txt,hs,s,*m,s2;
+ int i,hi,thisnr,ansiflag;
+
+ if (flag&M2S_REMOTE) txt="Rubrik: "+(group?group:GROUP)+", Artikel: "+
+ (intp(msg)?to_string(msg+1):"???")+" von "+sizeof(messages)+"\n";
+ else txt="";
+
+ if (intp(msg)) {
+ thisnr=msg;
+ msg=messages[msg];
+ } else thisnr=-1;
+ if (!msg) return 0;
+
+ ansiflag=(flag&M2S_VT100)&&(this_player()->QueryProp(P_TTY)!="dumb");
+
+ txt += (ansiflag?ANSI_BOLD:"")+ msg[M_TITLE]+(ansiflag?ANSI_NORMAL:"")+
+ " ("+msg[M_WRITER]+", "+
+ dtime(msg[M_TIME])[5..26]+"):\n";
+// if (geteuid(TP)=="sitopanaki") txt+="TID="+GetTID(msg)+"\n"; // Debug
+ if (!IS_STATUSLINE(msg[M_MESSAGE]))
+ return txt+"\n"+msg[M_MESSAGE];
+ m=explode(msg[M_MESSAGE],"\n");
+ while (IS_STATUSLINE(m[0])) {
+// txt+=m[0]+"\n"; // ###
+ if (sscanf(m[0],"%s rn=%s rt=%d rg=%s",hs,s,hi,hs)==4 ||
+ sscanf(m[0],"%s rn=%s rt=%d",hs,s,hi)==3)
+ {
+ int nr,h;
+ nr=-1;
+ if (pointerp(messages))
+ {
+ for (h=((thisnr>=0) ? thisnr-1 : sizeof(messages)-1);
+ (h>=0 && messages[h][M_TIME]>=hi);h--)
+ if (messages[h][M_TIME]==hi &&
+ lower_case(messages[h][M_WRITER])==lower_case(s))
+ nr=h;
+ }
+ txt+="[Bezug: Artikel "+((nr>=0) ? (nr+1) :
+ (hs==STATUSESCAPE||hs==(group?group:GROUP)?"(geloescht?)":"in "+hs))+
+ " von "+capitalize(s)+" vom "+dtime(hi)[5..26]+"]\n";
+ }
+ if (sscanf(m[0],"%s on=%s ot=%d og=%s",hs,s,hi,hs)==4) {
+ txt+="[Autor: "+s+", "+dtime(hi)[5..26]+", verlegt von "+hs+"]\n";
+ }
+ m=m[1..];
+ }
+ return txt+"\n"+implode(m,"\n");
+}
+
+static varargs lies(mixed str) {
+ mixed num;
+ mixed *messages;
+ int tid;
+
+ if (str=="?"||str=="-?") return
+ write("Syntax: lies <nr>\n"
+ " artikel <nr>\n"
+ "Siehe auch: nn\n"),1;
+
+ if (intp(str)) num=str;
+ if ((!num && (!str || str=="" || sscanf(str,"%d",num)!=1)) || num<=0) {
+ notify_fail("WELCHE Nachricht willst Du lesen?\n");
+ return 0;
+ }
+ if (!pointerp(messages=NEWSSERVER->GetNotes(GROUP)))
+ return notify_fail("Seltsam, die Rubrik '"+GROUP+
+ "' gibt es nicht mehr...\n"), 0;
+ num--;
+ if (sizeof(messages)<=num) {
+ notify_fail("So viele Artikel sind da nicht!\n");
+ return 0;
+ }
+
+ lasttitle=({messages[num][M_TITLE],messages[num][M_WRITER],
+ messages[num][M_TIME],GetTID(messages[num]),GROUP,num});
+ this_player()->More(Message2string(messages[num],messages,M2S_VT100));
+ if (this_player() && IS_LEARNER(this_player()))
+ this_player()->save_me(1);
+ return 1;
+}
+
+static varargs mixed GetGroupName(mixed g,mixed groups) {
+ /* Name einer Rubrik. g ist int oder string, enthaelt Name oder Nummer
+ (ab 1 numeriert) */
+ mixed i,expr,gg;
+ if (!g) return write("Du solltest schon die Rubrik angeben.\n"),0;
+ if (!groups) groups=NEWSSERVER->GetGroups();
+ if (intp(i=g) || sscanf(g,"%d",i)) {
+ if (i>0 && i<=sizeof(groups)) return groups[i-1];
+ write("Eine Rubrik mit der Nummer "+i+" gibt es leider nicht.\n");
+ return 0;
+ }
+ g=lower_case(g);
+ switch(g){
+ case ".": return GROUP;
+ case "+": return groups[(member(groups,GROUP)+1)%sizeof(groups)];
+ case "-":
+ return groups[(member(groups,GROUP)-1+sizeof(groups))%sizeof(groups)];
+ }
+
+ // Existiert die Rubrik genau so?
+ if (member(groups,g)>-1) return g;
+
+ g = regreplace(g,"[[\\]\\*()?]","",1);
+ // haerteres Kriterium: Alle Abschnitte angegeben
+ expr="^"+implode(explode(g,"."),"[^\\.]*\\.")+"[^\\.]*$";
+// write("REGEXP="+expr+"\n");
+ gg=regexp(groups,expr);
+ if (sizeof(gg)==1) return gg[0];
+
+ // weicheres Kriterium: Nicht alle Abschnitte angegeben
+ expr="^(.*\\.)*"+implode(explode(g,"."),".*\\.")+".*$";
+// write("REGEXP="+expr+"\n");
+ gg=regexp(groups,expr);
+
+ if (!sizeof(gg)) {
+ write("Eine Rubrik '"+g+"' gibt es hier leider nicht.\n");
+ return 0;
+ }
+
+ if (sizeof(gg)==1) return gg[0];
+
+ write(break_string("Die Rubrik "+g+" ist nicht eindeutig. Wahrscheinlich "
+ "meinst Du eine der folgenden: "+implode(gg,", ")+".\n",78));
+ return 0;
+}
+
+static rubrik(str)
+{
+ mixed *gruppen;
+ mixed news;
+ int anz,i;
+
+ if (str=="?"||str=="-?") return
+ write("Syntax: rubrik <rubrik>\n"
+ " wechselt die aktuelle Rubrik. Es wird die Nummer der Rubrik,\n"
+ " ihr Name oder jede eindeutige Abkuerzung akzeptiert.\n"),1;
+
+ if (!str || str==0) {
+ if (!pointerp(news=NEWSSERVER->GetNotes(GROUP))){
+ GROUP=DEFAULTGROUP;
+ if (!pointerp(news=NEWSSERVER->GetNotes(GROUP)))
+ return notify_fail("Seltsam, irgendwie geht hier einiges schief...\n"),0;
+ }
+ return write("Aktuelle Rubrik: "+GROUP+" ("+sizeof(news)+" Artikel).\n"),1;
+ }
+ str=GetGroupName(str);
+ if (!str) return 1;
+ GROUP=str;
+ news=NEWSSERVER->GetNotes(GROUP);
+ write(break_string("Ok, Du hast die Rubrik "+GROUP+" mit "+sizeof(news)+
+ " Artikel"+(sizeof(news)==1?"":"n")+" aufgeschlagen.\n",
+ 78));
+ return 1;
+}
+
+LiesArtikel(str) {
+ string s1;
+ int i1;
+ if ( !str ) return 0;
+ if (sscanf(str,"rubrik %s",s1))
+ return rubrik(s1);
+ if (sscanf(str,"%d",i1))
+ return lies(to_int(i1));
+ if (sscanf(str,"artikel %s",s1))
+ return lies(s1);
+}
+
+
+/* Ueberpruefe, ob in Rubrik tote threads ignoriert werden. Tot bedeutet,
+ dass der letzte darin uebergangene Artikel bereits expired ist UND
+ keine Artikel aus diesem thread mehr vorhanden sind.
+ ACHTUNG: Es kann passieren, dass dazwischen noch ein neuer Artikel
+ dazugekommen ist.
+ Hier wird auf expired geprueft und ggf Variable deadTID gesetzt. Wird beim
+ Lesen mit nn ein Artikel mit dieser TID gefunden (passiert direkt hinter
+ Pruefung), wird deadTID wieder auf 0 gesetzt. Ist deadTID beim Umschalten
+ auf naechste Rubrik !=0, ist der thread tot.
+*/
+
+static int CheckThreads(string rubrik,int timeout) {
+ mixed tids;
+ int i;
+
+// deadTID=0;
+ tids=m_indices(read_until[IGNOREGROUP][rubrik]);
+ for (i=sizeof(tids)-1;i>=0&&!deadTID;i--)
+ if (read_until[IGNOREGROUP][rubrik][tids[i]]<timeout) deadTID=tids[i];
+ return 1;
+}
+
+static int rubriken(mixed arg)
+{
+ mixed *gruppen, *messages;
+ mixed news;
+ int anz,i,lasttime,timeout,foundone;
+ string s;
+
+ if (arg=="?"||arg=="-?") return
+ write("Syntax: rubriken listet alle Rubriken\n"
+ " rubriken neu nur Rubriken mit ungelesenen Artikeln\n"),1;
+
+ gruppen=NEWSSERVER->GetGroups();
+ map(m_indices(read_until)-gruppen-SYSTEMGROUPS,#'KillGroup); // ');
+ s="\nEs gibt zur Zeit ";
+ anz=sizeof(gruppen);
+ if (anz==0) {
+ write(s+"keine Rubriken (wie seltsam ...)\n");
+ return 1;
+ }
+ s+=anz+" Rubrik"+(anz==1 ? "" : "en")+".";
+ if (arg=="neu") s+="\nDavon enthalten neue Artikel:\n\n";
+ else s+="\n(* oder x: enthaelt neue Artikel, x oder -: abbestellt, "
+ ">: aktuelle Rubrik)\n\n";
+ for (i=0;i<anz;i++) {
+ timeout=read_until[gruppen[i]];
+ /* GetNewsTime lieferte leider manchmal was falsches :-( */
+ /* jetzt hoffentlich richtig? Wenn nicht, das if ausklammern */
+ if ( arg!="neu" || (lasttime=NEWSSERVER->GetNewsTime(gruppen[i])) > timeout) {
+ messages=NEWSSERVER->GetNotes(gruppen[i]);
+ if (!messages || !sizeof(messages)) lasttime=0;
+ else lasttime=messages[sizeof(messages)-1][M_TIME];
+ foundone=1;
+ }
+ if (arg!="neu" || (timeout>=0 && lasttime>abs(timeout)))
+ s+=sprintf("%s%s%3d\. %-39.39s: ",
+ ((gruppen[i]==GROUP)?">":" "),
+ ((lasttime>abs(timeout)) ? ((timeout<0) ? "x" : "*")
+ : ((timeout<0) ? "-" : " ") ),
+ i+1,gruppen[i])+
+ (lasttime ? sprintf("%3d Artikel (%s)\n",
+ sizeof(messages),
+ // ((sizeof(messages)==1) ? ". " : "en."),
+ dtime(lasttime)[5..12]+ctime(lasttime)[<2..]) :
+ " - leer -\n");
+ }
+ if (arg=="neu"&&!foundone) s+="Keine Rubrik enthaelt neue Artikel.\n";
+ this_player()->More(s);
+ return 1;
+}
+
+#define M_READNEXT 1
+#define M_LISTNEW 2
+#define M_LISTNEWGR 3
+#define M_READGR 4
+
+static ReadNextUnread(str)
+{
+ string *groups,group;
+ mixed *messages;
+ int curgr,curmsg,timeout,start,nrgroups,sog,mode;
+
+ if (str=="mail") return Mail(0); /* NF Compatibility Special */
+
+ if (str=="?"||str=="-?") return
+ write("Syntax: nn naechster neuer Artikel\n"
+ " nn <rubrik> in entspr. Rubrik, wenn da was neu ist\n"
+ " nn rubriken Liste der Rubriken mit neuen Artikeln\n"
+ " nn liste Liste der ungelesenen Artikel\n"),1;
+
+ groups=NEWSSERVER->GetGroups();
+ deadTID=0;
+ map(m_indices(read_until)-groups-SYSTEMGROUPS,#'KillGroup); //'
+ nrgroups=sizeof(groups);
+ if (str && str!="rubriken" && str!="liste"){
+ if (!group=GetGroupName(str)) return 1;
+ }
+ else
+ group=0;
+ if (group && (curgr=member(groups,group)+1)) {
+ --curgr;
+ if (curgr<0 || curgr>=sizeof(groups))
+ return notify_fail("Nee... so eine Rubrik gibts hier nicht.\n"),0;
+ GROUP=group;
+ start=curgr+1;
+ mode=M_READGR;
+ write("Rubrik "+(curgr+1)+": "+GROUP+"\n");
+ } else {
+ switch (str) {
+ case 0: mode=M_READNEXT; break;
+ case "liste": mode=M_LISTNEW; write("Du hast noch nicht gelesen:\n"); break;
+ case "rubriken": return rubriken("neu");
+ default:
+ notify_fail("\
+Diesen Parameter verstehe ich nicht. Entweder gar nichts, \"liste\"\n\
+\"rubriken\", oder Name bzw. Nummer einer Rubrik.\n");
+ return 0;
+ }
+ curgr=member(groups,GROUP);
+ start=curgr+nrgroups;
+ }
+ if (!pointerp(messages=NEWSSERVER->GetNotes(GROUP))){
+ GROUP=DEFAULTGROUP;
+ if (!pointerp(messages=NEWSSERVER->GetNotes(GROUP)))
+ return notify_fail("Seltsam, irgendwie geht hier einiges schief...\n"),0;
+ }
+ timeout=read_until[GROUP];
+ curmsg=0;
+ sog=sizeof(messages);
+ while (curgr<start) {
+ ++curmsg;
+ if (curmsg>sog) {
+ if (deadTID)
+ read_until[IGNOREGROUP][GROUP]=
+ m_copy_delete(read_until[IGNOREGROUP][GROUP],deadTID);
+ ++curgr;
+ deadTID=0;
+ if (mode!=M_READGR) {
+ GROUP=groups[curgr%nrgroups];
+ timeout=read_until[GROUP];
+ if (!timeout) read_until[GROUP]=1; // Nimm neue Gruppen in Liste auf
+ if (timeout<0 || timeout>=NEWSSERVER->GetNewsTime(GROUP)) {
+ sog=0; /* Ueberlistung: Gruppe hat nix neues oder */
+ curmsg=1; /* ist unsubscribed */
+ }
+ else {
+ messages=NEWSSERVER->GetNotes(GROUP);
+ curmsg=0;
+ sog=sizeof(messages);
+ }
+ }
+ } else {
+ if ((timeout>=0 || mode==M_READGR) && messages[curmsg-1][M_TIME] > abs(timeout)) {
+ if (pointerp(this_player()->QueryProp(P_IGNORE)) &&
+ member(this_player()->QueryProp(P_IGNORE),
+ lower_case(messages[curmsg-1][M_WRITER])+".news") != -1) {
+ printf("Uebergehe ignorierten Artikel %d von %s in Rubrik %s.\n",
+ curmsg,messages[curmsg-1][M_WRITER],GROUP);
+ read_until[GROUP]=messages[curmsg-1][M_TIME];
+ if (TP) TP->SetProp(P_READ_NEWS,read_until);
+ } else if
+ (read_until[IGNOREGROUP]&&
+ read_until[IGNOREGROUP][GROUP]&&
+ CheckThreads(GROUP,messages[0][M_TIME])&& /* Tote threads weg */
+ read_until[IGNOREGROUP][GROUP][GetTID(messages[curmsg-1])]) {
+ printf("Uebergehe Artikel %d aus ignoriertem Thread.\n",curmsg);
+ read_until[IGNOREGROUP][GROUP][GetTID(messages[curmsg-1])]=
+ messages[curmsg-1][M_TIME];
+ if (deadTID&&deadTID==GetTID(messages[curmsg-1])) deadTID=0;
+ read_until[GROUP]=messages[curmsg-1][M_TIME];
+ if (TP) TP->SetProp(P_READ_NEWS,read_until);
+ } else {
+ write("\nRubrik "+(curgr%nrgroups+1)+": "+GROUP+", Artikel: "+curmsg+" von "+sog+"\n");
+ if (mode==M_LISTNEW) {
+ write(sprintf(" %-45s [%-11s] %s\n",messages[curmsg-1][M_TITLE],
+ messages[curmsg-1][M_WRITER],
+ dtime(messages[curmsg-1][M_TIME])[5..16]));
+ } else { /* mode == M_READNEXT || mode==M_READGR */
+ if (timeout>=0) read_until[GROUP]=messages[curmsg-1][M_TIME];
+ else read_until[GROUP]=-messages[curmsg-1][M_TIME];
+ if (TP) TP->SetProp(P_READ_NEWS,read_until);
+ return (lies(""+curmsg));
+ }
+ }
+ }
+ /* sonst mach einfach garnix. Schleife laeuft weiter. */
+ }
+ }
+ switch(mode) {
+ case M_LISTNEW: return 1;
+ case M_READNEXT: write((read_until[NNADWMSG]||"Nix Neues auf der Welt.")
+ +"\n"); break;
+ case M_READGR: write("Nix Neues in dieser Rubrik.\n"); break;
+ }
+ return 1;
+}
+
+
+static SetNNADWMSG(str) {
+ if (str=="?"||str=="-?") return
+ write("Syntax: zeitungsmeldung <neue Meldung> setzt Meldung\n"
+ " zeitungsmeldung loescht Meldung\n"),1;
+ if (!read_until[NNADWMSG]) {
+ write("Du hast zur Zeit keine eigene NNADW-Meldung definiert.\n");
+ if (!str) return 1;
+ }
+ else write("Deine alte NNADW-Meldung war:\n"+read_until[NNADWMSG]+"\n");
+ if (!str) {
+ read_until=m_copy_delete(read_until,NNADWMSG);
+ write("Meldung ist geloescht, es gilt wieder die Standardmeldung.\n");
+ } else {
+ read_until[NNADWMSG]=this_player()->_unparsed_args();
+ write("Deine neue Meldung lautet jetzt:\n"+read_until[NNADWMSG]+"\n");
+ }
+ if (TP) TP->SetProp(P_READ_NEWS,read_until);
+ return 1;
+}
+
+varargs int InterpretTime(mixed a,int flag) {
+ // string oder string *
+ // akzeptiert folgende Formate:
+ // dd.mm.jj (Rueckgabe: 0:00 des entsprechenden Tages)
+ // vor [<anz> d|tagen] [<anz> h|stunden] [<anz> m|minuten]
+ // flag=1: "inklusive": bei dd.mm.jj-Format 23:59:59 statt 0:00 Uhr
+
+ int i,j,k,t,nrargs;
+ string s;
+ if (stringp(a)) a=explode(a," ");
+
+// printf("%O\n",a);
+
+ if ((nrargs=sscanf(a[0],"%d.%d.%d",i,j,k))==3 ||
+ (nrargs=sscanf(a[0],"%d.%d.",i,j))==2) {
+ // Datum -> Zeit: Funktioniert im Zeitraum 1973 - ca. 2090
+ // in Zeitzonen mit ganzen Stunden ggue Rechneruhr.
+ if (nrargs==2)
+ k=70+time()/31536000;
+ if (k<70) k+=100;
+ if (k>1970) k-=1900;
+ if (k<70||k>150) return
+ write("Unzulaessiges Jahr (erlaubt: 70-heute).\n"),0;
+ t=(k-70)*31536000;
+
+ if (i<1||i>31) return write("Unzulaessiger Tag (erlaubt: 1-31).\n"),0;
+ if (j<1||j>12) return write("Unzulaessiger Monat (erlaubt: 1-12).\n"),0;
+// printf("%d.%d.%d\n",i,j,k);
+ s=ctime(t);
+ if ((j>2) && !(k%4)) t+=86400; // Schaltjahrkorrektur fuer Monate>=3
+ t+=({ 0, 2678400, 5097600, 7776000,
+ 10368000, 13046400, 15638400, 18316800,
+ 20995200, 23587200, 26265600, 28857600})[j-1];
+ t+=86400*(i-1);
+ t+=86400*(32-to_int(s[8..9])); // Schaltjahrkorrektur
+ t-=3600*to_int(s[11..12]); // Zeitzonenkorrektur
+ t-=3600*to_int(ctime(t)[11..12]); // Sommerzeitkorrektur
+// write("Kontrolle: "+dtime(t)+"\n");
+ if (nrargs==2 && t>time()) t-=31536000;
+ return (flag?t+86399:t);
+ }
+
+ t=0;
+ if (a[0]=="vor") for (i=sizeof(a)-1;i>0;i--) {
+ switch (a[i]) {
+ case "m":
+ case "minuten":
+ case "min":
+ case "minute":
+ t+=60*to_int(a[i-1]);
+ break;
+ case "h":
+ case "stunde":
+ case "stunden":
+ case "s":
+ t+=3600*to_int(a[i-1]);
+ break;
+ case "d":
+ case "tag":
+ case "tage":
+ case "t":
+ t+=86400*to_int(a[i-1]);
+ break;
+ default:
+ if (!to_int(a[i]))
+ write("Argumentfehler: Kann nichts mit '"+a[i]+"' anfangen.\n");
+ }
+ return time()-t;
+ }
+ else return write("Argumentfehler.\n"),0;
+}
+
+static Catchup(string str)
+{
+ int welche,zeit,i;
+ string gr;
+ mixed groups,news,args;
+
+ if (!pointerp(NEWSSERVER->GetNotes(GROUP)))
+ return notify_fail("Seltsam, die Rubrik '"+GROUP+
+ "' gibt es nicht mehr...\n"), 0;
+
+ str=this_player()->_unparsed_args(); // wg. Datum
+ if (str) str=lower_case(str);
+ else str=GROUP; // default: aktuelle Rubrik komplett.
+
+ if (str=="?"|| str=="-?") return CatchupSyntax();
+
+ // uebergehe Antworten (Thread ignorieren)
+ if (str&&(str[0..6]=="antwort"||str=="thread")) {
+ if (!pointerp(lasttitle)) return
+ write("Du hast bisher noch keinen Artikel gelesen, damit kann ich nicht wissen,\nwelchen Thread du uebergehen willst.\n"),1;
+ if (!read_until[IGNOREGROUP]) read_until[IGNOREGROUP]=([]);
+ if (!read_until[IGNOREGROUP][GROUP]) read_until[IGNOREGROUP][GROUP]=([]);
+ if (read_until[IGNOREGROUP][GROUP][lasttitle[3]]) {
+ read_until[IGNOREGROUP][GROUP]=m_copy_delete(read_until[IGNOREGROUP][GROUP],lasttitle[3]);
+ write("Dieser Thread wird jetzt nicht mehr uebergangen.\n");
+ } else {
+ read_until[IGNOREGROUP][GROUP][lasttitle[3]]=lasttitle[2];
+ write("Dieser Thread wird ab sofort uebergangen.\nFalls das ein Irrtum war, wiederhole den Befehl augenblicklich.\n");
+ }
+ if (TP) TP->SetProp(P_READ_NEWS,read_until);
+ return 1;
+ }
+
+ groups=NEWSSERVER->GetGroups();
+
+ args=explode(str," ");
+
+ // Uebergehe alles
+
+ if (args[0]=="alle" || args[0]=="alles" || args[0]=="all") {
+ if (sizeof(args)<=1) zeit=time()-1;
+ else if (args[1]!="bis") return CatchupSyntax();
+ else if (sizeof(args)<3) return CatchupSyntax();
+
+ else zeit=InterpretTime(args[2..],1);
+ if (zeit>time()) zeit=time()-1;
+ write("Uebergehe alle Rubriken bis "+dtime(zeit)+".\n");
+ for (welche=0;welche<sizeof(groups);++welche) {
+ gr=groups[welche];
+// zeit=NEWSSERVER->GetNewsTime(gr);
+ if (abs(read_until[gr])<zeit)
+ read_until[gr]=(read_until[gr]>=0)?zeit:-zeit;
+ if (TP) TP->SetProp(P_READ_NEWS,read_until);
+ }
+ return 1;
+ }
+
+ // Anzahl Artikel
+
+ if (sizeof(args)>=2 && args[1]=="artikel") {
+ if (!to_int(args[0])) return CatchupSyntax();
+ news=NEWSSERVER->GetNotes(GROUP);
+ for (i=sizeof(news)-1;i>=0&&news[i][M_TIME]>read_until[GROUP];i--);
+ welche=i+to_int(args[0]);
+ if (welche>=sizeof(news)) welche=sizeof(news)-1;
+ write("Uebergehe die naechsten "+(welche-i)+" Artikel in Rubrik "+
+ GROUP+"\n.");
+ if (welche>=0) {
+ zeit=news[welche][M_TIME];
+ read_until[GROUP]=(read_until[GROUP]>=0)?zeit:-zeit;
+ if (TP) TP->SetProp(P_READ_NEWS,read_until);
+ }
+ return 1;
+ }
+
+ // einzelne Rubrik.
+
+ if (!(gr=GetGroupName(args[0]))) return 1;
+ news=NEWSSERVER->GetNotes(gr);
+ if (!sizeof(news)) {
+ write("Rubrik "+gr+" ist leer.\n");
+ return 1;
+ }
+// zeit=news[sizeof(news)-1][M_TIME];
+ if (sizeof(args)<=1)
+ zeit=time();
+ else
+ if (args[1]!="bis") return CatchupSyntax();
+ else
+ zeit=InterpretTime(args[2..],1);
+ if (zeit>time()) zeit=time();
+ read_until[gr]=zeit;
+ if (TP) TP->SetProp(P_READ_NEWS,read_until);
+ write("Uebergehe "+gr+" bis "+dtime(zeit)+",\nletzter Artikel war vom "+
+ dtime(NEWSSERVER->GetNewsTime(gr))+"\n");
+ return 1;
+}
+
+
+static Ignore(str) {
+ if (str=="thread"||str=="antworten") return Catchup(str);
+ return 0;
+}
+
+static CatchupSyntax() {
+ write("Syntax des Befehls uebergehe (oder catchup):\n"
+ " uebergehe [rubrik] (default: aktuelle Rubrik)\n"
+ " uebergehe alles (in allen Rubriken)\n"
+ " uebergehe <anz> artikel (in akt. Rubrik)\n"
+ " uebergehe [rubrik]|alles bis <tag>.<monat>.[<jahr>]\n"
+ " uebergehe [rubrik]|alles bis vor <zeit> wobei\n"
+ " <zeit> = [<n> d|tage] [<n> h|stunden] [<n> m|min|minuten]\n"
+ " uebergehe thread|antworten (entspr. 'ignoriere thread')\n");
+
+ return 1;
+}
+
+
+static int UncatchupSyntax()
+{
+ notify_fail(
+ "Syntax: wiederhole <anz> [artikel]\n"
+ " wiederhole [ab vor] [<anz> m|minute[n]] [<anz> h|stunde[n]] [<anz> d|tag[e]]\n"
+ " wiederhole ab tag.monat[.jahr]\n"
+ " wiederhole alles\n"
+ "Der wiederhole- oder uncatchup-Befehl bezieht sich immer auf die aktuelle\n"
+ "Rubrik und markiert die angegebenen Artikel wieder als ungelesen.\n"
+ "Zeiten (2. Syntax) sind rueckwaerts ab aktueller Uhrzeit gerechnet.\n"),0;
+ return 0;
+}
+
+
+static Uncatchup(string str)
+{
+ mixed args;
+ int i,zeit;
+ int mode; // 0 = nix, 1=Anzahl Artikel, 2=Zeit, 3=alles
+
+ str=this_player()->_unparsed_args(); // wg. Datum
+ if ( !TP || !str || !stringp(str) || str=="?" || str=="-?" )
+ return UncatchupSyntax();
+
+ if (!pointerp(NEWSSERVER->GetNotes(GROUP)))
+ return notify_fail("Seltsam, die Rubrik '"+GROUP+
+ "' gibt es nicht mehr...\n"), 0;
+
+ args=({""})+explode(lower_case(str)," ");
+ if (args[1]=="ab") {
+ mode=2;
+ if (sizeof(args)<3)
+ return UncatchupSyntax();
+ zeit=InterpretTime(args[2..]);
+ } else {
+ zeit=time();
+ for (i=sizeof(args)-1;i>0;i--) {
+ switch(args[i]){
+ case "alles":
+ case "alle":
+ case "all":
+ if (mode&&mode!=3) return
+ notify_fail("Bitte nur Zeit ODER alles ODER Anzahl angeben!\n"),0;
+ mode=3;
+ break;
+ case "minuten":
+ case "minute":
+ case "m":
+ case "stunden":
+ case "stunde":
+ case "h":
+ case "tage":
+ case "tag":
+ case "d":
+ if (mode&&mode!=2) return
+ notify_fail("Bitte nur Zeit/Datum ODER alles ODER "
+ "Anzahl angeben!\n"),0;
+ mode=2;
+ zeit-=(((args[i][0]=='m') ? 60 :
+ ((args[i][0]=='s' || args[i][0]=='h') ? 3600 : 86400))
+ *to_int(args[i-1]));
+ i--;
+ break;
+ case "artikel":
+ if (mode&&mode!=1) return
+ notify_fail("Bitte nur Zeit/Datum ODER alles ODER "
+ "Anzahl angeben!\n"),0;
+ mode=1;
+ zeit=to_int(args[i-1]);
+ i--;
+ break;
+ case "ab":
+ return
+ notify_fail("Bitte nur Zeit/Datum ODER alles ODER "
+ "Anzahl angeben!\n"),0;
+ default:
+ if (!to_int(args[i]))
+ return notify_fail("Unbekanntes Argument '"+args[i]+
+ "'! Aktion abgebrochen.\n"),0;
+ if (mode&&mode!=1) return
+ notify_fail("Bitte nur Zeit/Datum ODER alles ODER "
+ "Anzahl angeben!\n"),0;
+ mode=1;
+ zeit=to_int(args[i]);
+ }
+ }
+ }
+
+ switch(mode){
+ case 0:
+ return notify_fail("Gib bitte irgendeine Einheit an "
+ "(Hilfe mit wiederhole -?)!\n");
+ case 2:
+ read_until[GROUP]=(read_until[GROUP]>=0)?zeit:-zeit;
+ write(break_string("Markiere alle Artikel in Rubrik "+GROUP+
+ " seit "+dtime(zeit)+" als ungelesen.\n",78));
+ break;
+ case 3:
+ read_until[GROUP]=(read_until[GROUP]>=0?1:-1);
+ write("Markiere die komplette Rubrik "+GROUP+" als ungelesen.\n");
+ break;
+ case 1:
+ write(break_string("Markiere die letzten "+zeit+
+ " gelesenen Artikel in Rubrik "+GROUP+" als ungelesen.\n",78));
+ { int h; mixed notes;
+ notes=NEWSSERVER->GetNotes(GROUP);
+ h=sizeof(notes)-1;
+ while ( (h>=0) && (abs(read_until[GROUP]) < notes[h][M_TIME]) ) {
+ h--;
+ }
+ if (h==-1||h<zeit)
+ read_until[GROUP]=
+ (read_until[GROUP]>=0)?1:-1;
+ else
+ read_until[GROUP]=(
+ (read_until[GROUP]>=0)?notes[h-zeit][M_TIME]
+ :-notes[h-zeit][M_TIME]);
+ }
+ }
+ write("Ok. Du kannst die als ungelesen markierten Artikel "
+ "mit nn nochmal lesen.\n");
+
+ if (TP) TP->SetProp(P_READ_NEWS,read_until);
+ return 1;
+}
+
+
+QueryRead() {
+ return read_until;
+}
+
+static CatchNewsError(int err,string text4minus3) {
+ switch (err) {
+ case 1: return 1;
+ case -1: write("Du darfst in dieser Rubrik nicht schreiben!\n"); return 0;
+ case -2: write("Die Rubrik gibt es nicht mehr, sehr seltsam...\n"); return 0;
+ case -3: write(text4minus3+"\n"); return 0;
+ default: write("Interner Fehler "+err+", Erzmagier verstaendigen!\n"); return 0;
+ }
+}
+
+static varargs schreib(str,pretext,called_by_itself,statuslines) {
+ int err;
+
+ if (str=="?"||str=="-?") {
+ write("Syntax: schreib <Titel>\n"
+ " beginnt einen neuen Artikel in der Zeitung.\n");
+ return 1;
+ }
+
+ if (!this_interactive() || !this_interactive()->query_real_name()) return 0;
+ if (!called_by_itself && extern_call() && !pretext)
+ str=this_interactive()->_unparsed_args()||"";
+ if (called_by_itself && str=="~q") {
+ write("Abgebrochen.\n");
+ return 1;
+ }
+ if (!CatchNewsError(
+ NEWSSERVER->AskAllowedWrite(GROUP),
+ "Diese Rubrik ist leider schon randvoll!")) return 1;
+ if (!called_by_itself)
+ write("Neuer Artikel in Rubrik "+GROUP+":\n");
+ if (!str || str=="" || str=="artikel") {
+ input_to("schreib", INPUT_PROMPT, "Titel des Artikels: ", pretext,1);
+ return 1;
+ }
+ // writer=this_interactive()->query_real_name();
+ message=allocate(6);
+ message[M_BOARD]=GROUP;
+ message[M_TITLE]=killctrl(str);
+ message[M_MESSAGE]=statuslines;
+ write("Titel ist: "+str+".\n\
+Gib jetzt Deinen Text ein,\n\
+** oder . wenn Du fertig bist, ~q zum Abbrechen, ~h fuer eine Hilfsseite.\n");
+ nedit("PostNote",pretext);
+ return 1;
+}
+
+static varargs Reply(string str,string newtitle) {
+ mixed dummy,replytitle,s;
+ int nr;
+
+ if ((dummy=(str||newtitle))=="?"||dummy=="-?") {
+ write("Der Antworte-Befehl ist doppelt belegt.\n"
+ "1. (Zeitung): Schreibe Antwort auf einen Artikel in der Zeitung.\n"
+ " Syntax: antworte\n"
+ " antworte auf artikel <nr> [neuer Titel]\n"
+ " reply [auf artikel <nr> | to note <nr>] [neuer Titel]\n"
+ "2. aehnlich 'sage':\n"
+ " Du tippst zum Beispiel:\n"
+ " antworte ja, das weiss ich\n"
+ " Alle Spieler im Raum sehen dann:\n"
+ " <Dein Name> antwortet: ja, das weiss ich.\n"
+ "Bitte beachte, dass jede Syntax, die auf den antworte-Befehl der "
+ "Zeitung\npasst, auch von der Zeitung ausgewertet wird.\n");
+ return 1;
+ }
+
+ if (str&&
+ ((sscanf(lower_case(str),"auf artikel %d",dummy)==1 &&
+ str=this_player()->_unparsed_args()[12..])||
+ (sscanf(lower_case(str),"to note %d",dummy)==1 &&
+ str=this_player()->_unparsed_args()[8..]))) {
+ mixed notes;
+ notes=NEWSSERVER->GetNotes(GROUP);
+ if (dummy<1||dummy>sizeof(notes))
+ return write("Einen Artikel mit der Nummer "+dummy+
+ " gibt es in dieser Rubrik nicht.\n"),1;
+ dummy--;
+ replytitle=({notes[dummy][M_TITLE],notes[dummy][M_WRITER],
+ notes[dummy][M_TIME],GetTID(notes[dummy]),GROUP});
+ DEBUGVAR(str);
+ if (!newtitle&&str&&sizeof(str)&&sscanf(str,"%d %s",dummy,str)==2)
+ newtitle=str;
+ }
+ else if (!str||!sizeof(str)) {
+ if (!lasttitle) return
+ write("Du hast noch gar nichts gelesen, worauf Du "
+ "antworten koenntest.\n"),1;
+ replytitle=lasttitle;
+ }
+ else return 0;
+
+// return ComposeReply(replytitle);
+//}
+//
+//
+//ComposeReply(mixed replytitle) {
+
+ if (!newtitle) {
+ if (replytitle[0][0..7]=="Re: Re: ") newtitle="Re^3: "+replytitle[0][8..];
+ else if (sscanf(replytitle[0],"Re^%d: %s",nr,newtitle))
+ newtitle="Re^"+(nr+1)+": "+newtitle;
+ else newtitle="Re: "+replytitle[0];
+ }
+ return schreib(newtitle,0,0,
+ STATUSESCAPE+" rn="+replytitle[LAST_WRITER]+
+ " rt="+replytitle[LAST_TIME]+
+ " rg="+replytitle[LAST_GROUP]+"\n"+
+ STATUSESCAPE+" tid="+replytitle[LAST_TID]+"\n");
+}
+
+static Reply2(str) {
+ str = this_player()->_unparsed_args();
+ if (!str||str[0..11]=="auf artikel "||str[0..7]=="to note ")
+ return Reply(str);
+ return Reply(0,str);
+}
+
+static void InformPlayers(string group,string player,string text)
+{
+ object *players;
+ int i;
+ mixed data;
+ string ig;
+
+ players=users();
+ ig=lower_case(player)+".news";
+ for (i=sizeof(players)-1;i>=0;i--) {
+ data=players[i]->QueryProp(P_WAITFOR);
+ if (pointerp(data)&&(member(data,"Mpa")>-1)) {
+ data=players[i]->QueryProp(P_READ_NEWS);
+ if (mappingp(data)&&(data[group]>0)) {
+ data=players[i]->QueryProp(P_IGNORE);
+ if ((!pointerp(data))||(member(data,ig)==-1))
+ tell_object(players[i],text);
+ }
+ }
+ }
+}
+
+static PostNote(text) {
+ int err;
+ string sig;
+
+ if (!text) {
+ write("Abbruch! Artikel landet im Reisswolf.\n");
+ return 1;
+ }
+ if (!sizeof(old_explode(text,"\n")-
+ ({"q","quit"," **","** ","ende","","exit"," "})
+ ) )
+ return write("\
+ACHTUNG: Wolltest Du wirklich einen Artikel ohne Inhalt in die mpa setzen?\n\
+Artikel ohne erkennbaren Inhalt werden NICHT veroeffentlicht. Bitte ueber-\n\
+pruef Deine Syntax, falls Du keinen Artikel schreiben wolltest, oder schreib\n\
+auch ein bisschen Text!\n\
+Artikel landet im Reisswolf.\n"),1;
+ if (!message[M_MESSAGE])
+ message[M_MESSAGE] = text;
+ else
+ message[M_MESSAGE]+=text;
+ if (sig=read_file("/players/"+geteuid(this_interactive())+"/.signature"))
+ message[M_MESSAGE]+=sig;
+ if (!CatchNewsError(NEWSSERVER->WriteNote(message),
+ "Diese Rubrik ist voll. Mist, da war jemand schneller...")) {
+ write("Versuch, Platz in der Rubrik zu finden, dann kannst Du mir ~r nochmal\nin den Text einsteigen und ihn anschliessend veroeffentlichen.\n(Vorschlag: Einen veralteten Artikel abhaengen oder verlegen.\n");
+ return 0;
+ }
+ write("OK, Artikel ist veroeffentlicht.\n");
+ say(capitalize(TP->name())+
+ " hat einen Artikel in der Zeitung veroeffentlicht.\n");
+ if (geteuid(TP)!="sitopanaki")
+ InformPlayers(message[M_BOARD],geteuid(this_interactive()),
+ "* MPA: Neuer Artikel von "+
+ capitalize(geteuid(this_interactive()))+
+ " in Rubrik \""+message[M_BOARD]+"\".\n");
+ message=0; /* Platz sparen! */
+ return 1;
+}
+
+
+//static // allowing aliasing *Rumata* 5/8/96
+inhalt(str) {
+ int i,endflag,timeout;
+ string *gruppen,s,txt,suche;
+ mixed messages;
+
+ if (str=="?"||str=="-?") return
+ write("Syntax: inhalt [<rubrik>] [ende] [suche <text>]\n"),1;
+
+ str=(!str)?({}):explode(str," ");
+
+ if (sizeof(str) && (str[0]=="neu" || str[0]=="neues") )
+ return ReadNextUnread("liste"),1;
+
+ if (endflag=member(str,"ende")+1) str-=({"ende"});
+ if (((i=member(str,"suche")) != -1) && (sizeof(str) > i)) {
+ suche=lower_case(implode(str[i+1..]," "));
+ str=str[0..i-1];
+ }
+ else
+ suche=0;
+ if (!sizeof(str)) {
+ str=GROUP;
+ if (!pointerp(messages=NEWSSERVER->GetNotes(str))){
+ str=GROUP=DEFAULTGROUP;
+ if (!pointerp(messages=NEWSSERVER->GetNotes(str)))
+ return notify_fail("Seltsam, irgendwie geht hier einiges schief...\n"),0;
+ }
+ }
+ else {
+ str=GetGroupName(str[0]);
+ if (!str) return 1;
+ messages=NEWSSERVER->GetNotes(str);
+ }
+ timeout=abs(read_until[str]);
+ s="Inhalt der Rubrik "+str+":\n\n";
+ if (!pointerp(messages) || !sizeof(messages))
+ return
+ write(s+"Zur Zeit befinden sich keine Artikel in dieser Rubrik.\n"),1;
+ if (suche)
+ s+="Suche nach '"+suche+"' in der Rubrik ergab folgende Treffer:\n\n";
+ else
+ if (sizeof(messages)==1)
+ s+="Zur Zeit befindet sich ein Artikel in der Rubrik:\n\n";
+ else
+ s+="Zur Zeit befinden sich "+sizeof(messages)+
+ " Artikel in der Rubrik:\n\n";
+ if (endflag&&(sizeof(messages)>16)&&
+ messages[sizeof(messages)-16][M_TIME]>=timeout) timeout=-1;
+ for (i=(endflag?(((endflag=sizeof(messages)-15)<0)?0:endflag):0);
+ i<sizeof(messages);i++)
+ {
+ txt=sprintf("%2d.%s%-48s%4d (%-11s) %s\n",i+1,
+ (((timeout>=0) && timeout<messages[i][M_TIME] )?
+ ( (timeout=-1),"*"):" "),messages[i][M_TITLE],
+ sizeof(explode(messages[i][M_MESSAGE],"\n")),
+ messages[i][M_WRITER],
+ dtime(messages[i][M_TIME])[5..11]);
+ if (!suche || (strstr(lower_case(txt), suche) != -1))
+ s+=txt;
+ }
+ if (endflag) write(s);
+ else this_player()->More(s);
+ return 1;
+}
+
+
+static artikel(str) {
+ return lies(str);
+}
+
+
+static loesche(str) {
+ int num;
+ mixed *messages;
+
+ if (str=="?"||str=="-?") return
+ write("Syntax: loesche artikel <nr>\n"
+ " (bezieht sich immer auf die aktuelle Rubrik.\n"),1;
+
+ if (!str || sscanf(str,"artikel %d",num)!=1 || num<=0)
+ return notify_fail("WELCHEN Artikel willst Du loeschen ?\n"),0;
+ num--;
+ messages=(NEWSSERVER->GetNotes(GROUP));
+ if (sizeof(messages)<=num) return
+ notify_fail("So viele Artikel sind da nicht!\n"),0;
+
+ write("Rubrik "+GROUP+", Artikel "+(num+1)+
+ " von "+capitalize(messages[num][M_WRITER])+
+ " vom "+dtime(messages[num][M_TIME])[5..26]+
+ ",\nTitel: "+messages[num][M_TITLE]+",\n\n");
+
+ /* (ueberfluessige Abfrage, macht schon /secure/news)
+ if (!IS_LEARNER(TI) && lower_case(messages[num][M_WRITER])!=geteuid(TI))
+ return
+ write("Nicht geloescht - du darfst nur eigene Artikel loeschen.\n"),1;
+ */
+
+ switch (NEWSSERVER->RemoveNote(GROUP, num)){
+ case 1: write("Artikel ist geloescht.\n");
+ say(this_player()->name()+" loescht einen Artikel aus der Zeitung.\n");
+ return 1;
+ case -1: write("Diesen Artikel darfst Du nicht loeschen.\n");
+ say(this_player()->name()+" versucht vergeblich, einen Artikel zu loeschen.\n");
+ return 1;
+ case -3: write("So viele Artikel sind da nicht !\n");
+ return 1;
+ default: write("Interner Fehler. Bitte Erzmagier verstaendigen !\n");
+ return 1;
+ }
+}
+
+// Low-level Funktion zum Abonnieren/Abbestellen von Rubriken
+// bestellen==0 -> abbestellen, bestellen!=0 -> bestellen
+// Rueckgabe: 0, wenn der gewuenschte Zustand schon eingestellt war, sonst 1
+private int _subscribe(string groupname, int bestellen) {
+
+ int timeout = read_until[groupname];
+ // gar nicht abonniert/abbestellt?
+ if (!bestellen && timeout < 0)
+ return 0;
+ else if (bestellen && timeout > 0)
+ return 0;
+
+ // wenn noch kein timeout, erstmal auf 1 setzen
+ timeout ||= 1;
+
+ // -1 fuer abbestellen, +1 fuer bestellen
+ if (bestellen)
+ read_until[groupname] = abs(timeout);
+ else
+ read_until[groupname] = -timeout;
+
+ if (environment())
+ environment()->SetProp(P_READ_NEWS, read_until);
+
+ return 1;
+}
+
+static Unsubscribe(str) {
+ int timeout;
+ if (str=="?"||str=="-?") return
+ write("Syntax: unsubscribe <rubrik>"
+ " oder: bestelle <rubrik> ab\n"),1;
+ str=GetGroupName(str);
+ if (!str) return 1;
+ if (!_subscribe(str,0)) {
+ notify_fail("Die Rubrik hast Du gar nicht abonniert!\n");
+ return 0;
+ }
+ else {
+ write("Rubrik "+str+" abbestellt.\n");
+ }
+ return 1;
+}
+
+
+static Bestelle(str) { /* ab ! */
+ if (!str || !sscanf(str,"%s ab",str)) return _notify_fail(
+ "Die Syntax ist: 'bestelle <rubrik> ab', "
+ "oder meinst Du 'abonniere'?\n"),0;
+ return Unsubscribe(str);
+}
+
+static Subscribe(str) {
+ int timeout;
+ if (str=="?"||str=="-?") return
+ write("Syntax: abonniere <rubrik>\n"
+ " oder: subscribe <rubrik>\n"),1;
+ str=GetGroupName(str);
+ if (!str) return 1;
+ if (!_subscribe(str,1)) {
+ notify_fail("Die Rubrik hast Du doch schon abonniert!\n");
+ return 0;
+ }
+ else {
+ write("Rubrik "+str+" abonniert.\n");
+ }
+ return 1;
+}
+
+// Legt die anfaenglichen Abonnements eines Neulesers fest und bestellt alle
+// anderen ab.
+private void InitialSubscriptions() {
+ // alle abbestellen. ;-)
+ // Alternative: fuer alle _subscribe(,0) rufen
+ if (!query_once_interactive(environment()))
+ return;
+ string *gruppen = NEWSSERVER->GetGroups();
+ int *vals = allocate(sizeof(gruppen),-1);
+ read_until = mkmapping(gruppen,vals);
+
+ // jetzt die vorausgewaehlten bestellen
+ foreach(string gruppe : INITIAL_SUBSCRIPTIONS) {
+ if (member(gruppen, gruppe) > -1)
+ _subscribe(gruppe,1);
+ }
+ // und ggf. noch die eigene Gildenrubrik
+ string gilde = environment()->QueryProp(P_GUILD);
+ if (stringp(gilde)
+ && member(gruppen, "gilden."+gilde) > -1)
+ _subscribe("gilden."+gilde,1);
+
+ environment()->SetProp(P_READ_NEWS, read_until);
+}
+
+static MoveMessage(str) {
+ int num,i;
+ mixed msg/*,expl*/;
+ string gr;
+ if (str=="?"||str=="-?") return
+ write("Syntax: verlege artikel <nr> nach <rubrik>\n"
+ " Artikel und Rubrik muessen explizit angegeben werden.\n"),1;
+ if (!str || sscanf(str,"artikel %d nach %s",num,gr)!=2) return (int)notify_fail(
+ "verlege artikel <nr> nach <rubrik>, oder was?\n");
+ if (!(gr=GetGroupName(gr))) return 1;
+ if (!(CatchNewsError(NEWSSERVER->AskAllowedWrite(gr),"Die Rubrik ist leider voll.\n"))) return 1;
+
+ if (!pointerp(msg=NEWSSERVER->GetNotes(GROUP)))
+ return notify_fail("Seltsam, die Rubrik '"+GROUP+
+ "' gibt es nicht mehr...\n"), 0;
+
+ num--;
+ if (sizeof(msg)<=num) return
+ notify_fail("So viele Nachrichten sind da nicht !\n"),0;
+ msg=msg[num];
+ if (geteuid(TI) != lower_case(msg[M_WRITER])) {
+ if (!IS_LEARNER(TI)) return
+ write("Du darfst nur Deine eigenen Artikel verlegen.\n"),1;
+ write("WARNUNG: Das ist nicht Dein eigener Artikel!\n");
+ }
+ // return (int)notify_fail("Man darf zur Zeit nur eigene Artikel verlegen.\n");
+ if (!CatchNewsError(NEWSSERVER->RemoveNote(GROUP,num),"Dieser Fehler kann eigentlich nicht auftreten"))
+ write("Warnung! Konnte Artikel an alter Position nicht loeschen.\n");
+ else write("Artikel von Rubrik "+GROUP+" entfernt.\n");
+
+ msg[M_MESSAGE]=
+ sprintf("%s on=%s ot=%d og=%s\n",
+ STATUSESCAPE,msg[M_WRITER],msg[M_TIME],msg[M_BOARD])
+ +msg[M_MESSAGE];
+
+/*
+ expl=explode(msg[M_MESSAGE],"\n");
+ for (i=0;(IS_STATUSLINE(expl[i][0..2]));i++);
+ msg[M_MESSAGE]=( (i) ? implode(expl[0..i-1],"\n")+"\n" : "" ) +
+ "[Verlegt von "+msg[M_BOARD]+", "+msg[M_WRITER]+", "+
+ dtime(msg[M_TIME])[5..26]+"]:\n"+
+ implode(expl[i..],"\n")+"\n";
+*/
+
+ msg[M_BOARD]=gr;
+ NEWSSERVER->WriteNote(msg);
+ write("Artikel nach Rubrik "+gr+" verlegt.\n");
+ return 1;
+}
+
+static MoveTrash()
+{
+ if (!pointerp(lasttitle)||sizeof(lasttitle)<LAST_SIZEOF) return
+ write("Was denn bitte? Du hast noch gar nichts gelesen!\n"),1;
+ if (lasttitle[LAST_GROUP]!=GROUP) return
+ write("Nix gibts! Du hast die Rubrik gewechselt!\n"),1;
+ return MoveMessage(sprintf("artikel %d nach muell",lasttitle[LAST_NR]+1));
+}
+
+static SaveMessage(str) {
+ mixed num;
+ mixed *messages;
+
+ if (intp(str)) num=str;
+ if ((!num && (!str || str=="" || sscanf(str,"artikel %d",num)!=1)) || num<=0) {
+ notify_fail("Welchen Artikel willst Du abspeichern?\n");
+ return 0;
+ }
+ if (!pointerp(messages=NEWSSERVER->GetNotes(GROUP)))
+ return notify_fail("Seltsam, die Rubrik '"+GROUP+
+ "' gibt es nicht mehr...\n"), 0;
+ num--;
+ if (sizeof(messages)<=num) {
+ notify_fail("So viele Nachrichten sind da nicht !\n");
+ return 0;
+ }
+ if(write_file(SAVEMSGPATH(TP),Message2string(num,messages,M2S_REMOTE)+"\n"))
+ write(break_string(
+ "Inhalt des Artikels wurde nach "+SAVEMSGPATH(TP)+" gespeichert.\n"));
+ else
+ write(break_string(
+ "Fehler beim Schreiben nach "+SAVEMSGPATH(TP)+"!\n"));
+ return 1;
+}
+
+
+static MailMessage(str) {
+ mixed num,rec,group;
+ mixed *messages;
+
+// printf("%O\n",inherit_list(environment(TP)));
+// if (member(query_actions(this_player()),"mail")<0)
+// tut nicht wegen anderer Implemtierung von AddCmd in Raeumen
+
+ if (str=="?"||str=="-?") return
+ write("Syntax: versende artikel <nr> an <adresse>\n"),1;
+
+ str=TP->_unparsed_args(); // wegen Mailadressen
+ if (str) str=lower_case(str);
+
+ if (!IS_SEER(TP) && !IS_POST(environment(TP)))
+ return notify_fail("Du musst in ein Postamt gehen, "
+ "um etwas versenden zu koennen.\n"),0;
+
+ num=0;
+
+ if (!str || (sscanf(str,"artikel %d an %s",num,rec)!=2 &&
+ sscanf(str,"note %d to %s",num,rec)!=2 &&
+ sscanf(str,"note to %s",rec)!=1 &&
+ sscanf(str,"artikel an %s",rec)!=1)){
+ if (!str || str[0..6]=="artikel"||str[0..3]=="note") return
+ write("Welchen Artikel willst Du versenden, und wohin?\n"),1;
+ else return
+ notify_fail("Welchen Artikel willst Du versenden, und wohin?\n"),0;
+ }
+ if (!num&&(!pointerp(lasttitle)||sizeof(lasttitle)<LAST_SIZEOF))
+ return write("Du hast scheinbar noch nichts gelesen, worauf man sich "
+ "beziehen kann.\nGib notfalls die Nummer des Artikels an.\n"),1;
+
+ // printf("lasttitle= %O\nnum=%d\n",lasttitle,num);
+
+ if (!pointerp(messages=
+ NEWSSERVER->GetNotes(group=(num?GROUP:lasttitle[LAST_GROUP]))))
+ return notify_fail("Seltsam, die Rubrik gibt es nicht mehr...\n"), 0;
+
+ if (!pointerp(messages)||!sizeof(messages))
+ return write("Die Rubrik "+group+" ist leer.\n"),1;
+ if (num<0||sizeof(messages)<num) return
+ write("Einen Artikel mit Nummer "+num+" gibt es in Rubrik "+group+
+ " nicht!\n"),1;
+
+ if (num) num--;
+ else {
+ int h;
+ num=-1;
+ if (pointerp(messages)) {
+ for (h=sizeof(messages)-1;
+ (h>=0 && messages[h][M_TIME]>=lasttitle[LAST_TIME]);h--)
+ if (messages[h][M_TIME]==lasttitle[LAST_TIME] &&
+ lower_case(messages[h][M_WRITER])==
+ lower_case(lasttitle[LAST_WRITER]))
+ num=h;
+ }
+ if (num<0)
+ return notify_fail("Konnte Artikel nicht wiederfinden, "
+ "bitte gib die Nummer an.\n"),0;
+ }
+ MAILER->do_mail( rec,
+ "MPA: "+messages[num][M_TITLE]+" ("+messages[num][M_WRITER]+")",
+ Message2string(num,messages,M2S_REMOTE,group)+"\n");
+ return 1;
+}
+
+
+
+HelpPage(str) {
+ if (str!="mpa"&&str!="zeitung") return 0;
+ this_player()->More(read_file(HELPPAGE)+
+ (IS_LEARNER(TP) ? read_file(WIZHELPPAGE) : ""));
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
+
+protected void NotifyMove(object dest, object oldenv, int method) {
+ ::NotifyMove(dest, oldenv, method);
+
+ // P_READ_NEWS aus dem Spieler holen.
+ if (objectp(environment()) && query_once_interactive(environment())) {
+ read_until=environment()->QueryProp(P_READ_NEWS);
+ }
+
+ if (!mappingp(read_until) || !sizeof(read_until))
+ InitialSubscriptions();
+}
+
+int GetTID(mixed message) {
+ string dummy;
+ int tid;
+ return (sscanf(message[M_MESSAGE],"%s" STATUSESCAPE " tid=%d",dummy,tid)==2)
+ ? tid : message[M_TIME];
+}
+