blob: 7bd197295c6673f289c7a27f8a4d48f5895a190c [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001/* Das Servicepaket der Morgengrauen-Presseagentur. Eine erweiterte Zeitung.
2 Teilweise zur alten Zeitung identisch.
3
4 unter Verwendung der Zeitung von Jof, voellig umgeschrieben.
5
6 (C) Nov 1993 - 1996 Loco@Morgengrauen
7
8 Verwendung ausserhalb von Morgengrauen ist gestattet unter folgenden
9 Bedingungen:
10 - Benutzung erfolgt auf eigene Gefahr. Jegliche Verantwortung wird
11 abgelehnt. Bugs ausserhalb von MG sind nicht mein Problem.
12 - Auch in veraenderten oder abgeleiteten Objekten muss ein Hinweis auf
13 die Herkunft erhalten bleiben.
14 - Bitte fragt mich vorher!
15 Ein Update-Service besteht nicht. Ruecknahme dieser Lizenz ist jederzeit
16 moeglich. Und wer nicht in der Lage ist, neue Versionen selber anzupassen,
17 hat in der Administration eines Muds nichts zu suchen.
18
19
20 04.11.93 Erste brauchbare Version
21 (... seitdem viele Aenderungen ...)
22 13.09.95 ca 02:00 erwarte mpa
23 13.09.95 ca 23:00 RebuildGroupList()
24 15.09.95 vorlaeufig ausgebaut
25 16.09. anders wieder eingebaut, und Kleinigkeiten
26 05.12.95 ca 19:20 Spieler koennen nur noch eigene Artikel loeschen/verl.
27 07.12.95 ca 23:00 Keine Anzeige der Statuszeile. Statuszeilen beginnen
28 mit ~#!, sind damit nicht mit dem Editor erzeugbar.
29 20.12.95 ca 17:00 uebergehe thread/antworten
30 31.01.96 wiederhole/uncatchup
31 22.04.96 Aufraeumen ignorierter threads. ALPHA!
32 24.04.96 + - . als Adressierungen, zeitungsmeldung
33 02.10.96 Kleinigkeiten
34 08.10.96 Kleinigkeiten
35 05.12.96 antworte auf artikel <nr>, reply <neuer titel>,
36 versende artikel, Abkuerzungen fuer Rubrikennamen,
37 Layoutaenderungen,
38 Herkunft bei verlegten Artikeln in Statuszeile
39
40 Letzte Aenderung:
41 04.11.06 Zesstra Anpassung an das neue Verhalten von inherit_list() in LD
42
43*/
44
45#include <properties.h>
46#include <language.h>
47#include <news.h>
48#include <wizlevels.h>
49#include <ansi.h>
50#include <input_to.h>
51#include "/mail/post.h"
52
53inherit "/std/thing";
54inherit NEDIT;
55/*
56#define DEBUG(x) if (funcall(symbol_function('find_player),"zesstra"))\
57 tell_object(funcall(symbol_function('find_player),"zesstra"),\
58 "MPA: "+x+"\n")
59#define DEBUGVAR(x) DEBUG(sprintf(x+":\n%O\n",x))
60*/
61#define DEBUGVAR(x)
62
63// Konfiguration, ggf mudabhaengig
64#define DEFAULTGROUP "allgemeines"
65#define MINIHELPPAGE "p/service/loco/doc/mini-mpa.txt"
66#define HELPPAGE "/p/service/loco/doc/mpa"
67#define WIZHELPPAGE "/p/service/loco/doc/mpa.wiz"
68#define SAVEMSGPATH(pl) ("/open/News/"+(geteuid(pl))+".news")
69#define IS_POST(r) (member(inherit_list(r),STDPOST+".c")>=0)
70#define INITIAL_SUBSCRIPTIONS \
71 ({ "bekanntmachungen", \
72 "d.ebene", \
73 "d.wueste", \
74 "d.inseln", \
75 "d.unterwelt", \
76 "d.dschungel", \
77 "d.gebirge", \
78 "d.polar", \
79 "d.wald", \
80 "d.fernwest", \
81 "d.vland", \
82 "d.anfaenger", \
83 "entwicklung", \
84 })
85
86// Makros etc.
87
88#define TP this_player()
89#define TI this_interactive()
90#define STATUSESCAPE "~#!"
91#define IS_STATUSLINE(s) ((s[0..1]=="#!")||(s[0..2]=="~#!"))
92//#define IS_STATUSLINE(s) (s[0..2]=="~#!")
93// in Rubrik muell fanden sich tatsaechlich noch solche uralten notes...
94#define IGNOREGROUP "*ignored*"
95#define NNADWMSG "*NNADWMSG*"
96#define SYSTEMGROUPS ({IGNOREGROUP,NNADWMSG})
97
98// Aufbau der ignoregroup:
99// ([group1:([tid1:lasttime1,tid2:lasttime2,...]),group2:...])
100
101// Flags fuer Message2string()
102#define M2S_VT100 1
103#define M2S_ANSI M2S_VT100
104#define M2S_REMOTE 2
105
106// Format von lasttitle
107#define LAST_TITLE 0
108#define LAST_WRITER 1
109#define LAST_TIME 2
110#define LAST_TID 3
111#define LAST_GROUP 4
112#define LAST_NR 5
113#define LAST_SIZEOF 6
114
115
116mapping read_until;
117mixed lasttitle; // Aufbau s.o.
118mixed message;
119int deadTID;
120string GROUP;
121
122int GetTID(mixed message);
123private void InitialSubscriptions();
124
125create()
126{
127 ::create();
128 seteuid(getuid());
129 GROUP="bekanntmachungen";
130 SetProp(P_SHORT,"Die Zeitung");
131 SetProp(P_NAME,"Zeitung");
132 SetProp(P_WEIGHT, 50);
133 SetProp(P_SIZE, 35);
134 SetProp(P_MATERIAL, ([MAT_PAPER: 100]) );
135 SetProp(P_GENDER, FEMALE);
136 AddId(({"nn","zeitung","servicepaket","mpa"}));
137 SetProp(P_NODROP,
138 "Das persoenliche Servicepaket der MPA kann man nicht wegwerfen.\n");
139 SetProp(P_NEVERDROP, 1);
140
141 if (!read_until) read_until=(["muell":-1]);
142}
143
144static mixed _query_read_msg() { return long(); }
145
146long() {
147 return "\
148Dies ist das Servicepaket der MPA (Morgengrauens Presse Agentur) -\n\
149die Zeitung des Morgengrauens.\n\
150Du kannst damit aktuelle Artikel lesen und schreiben, mit folgenden Befehlen:\n\
151 'nn [rubrik]' (Neueste Nachrichten) wuehlt die Rubrik durch und schaut,\n\
152 ob was neu ist. Der erste ungelesene Artikel wird angezeigt.\n\
153 Ohne Argument werden alle Rubriken durchwuehlt.\n\
154 'hilfe mpa' Ausfuehrliche Hilfsseite. Lesen dringend empfohlen!\n\
155Weitere Befehle:\n\
156 rubriken [neu] bestelle <rubrik> ab\n\
157 [lies ]rubrik <rubrik> abonniere <rubrik>\n\
158 inhalt [<rubrik>|neu|suche <text>] wiederhole ...\n\
159 nn <rubriken>|<liste> uebergehe ...\n\
160 [lies ]artikel <nummer>"+
161 ( (IS_LEARNER(TP)) ? " speichere artikel <nr>" : "" )+"\n\
162 schreib <titel> versende artikel [nr] an <adresse>\n\
163 antworte [auf artikel <nr>] [titel] verlege artikel <nr> nach <rubrik>\n\
164 loesche artikel <nr> zeitungsmeldung [neue Meldung]\n\
165 verbrenne zeitung wenn Dir alles zuviel wird....\n\
166"+ (IS_SEER(TP) ? "\
167Mit 'mail' bzw 'mail <spieler>' kannst Du Post lesen und schreiben.\n\
168" : "" )+"\
169Eingebaute aliase: note, catchup, reply, unsubscribe, subscribe, uncatchup.\n\
170Viele Befehle geben mit '<befehl> ?' einige Syntaxhinweise.\n\
171Aktuelle Rubrik: "+GROUP+"\n\
172";
173}
174
175
176init()
177{
178 ::init();
179
180 add_action("schreib","schreib");
181 add_action("schreib","schreibe");
182 add_action("schreib","note");
183 add_action("LiesArtikel","lies");
184 add_action("artikel","artikel");
185 add_action("loesche","loesch");
186 add_action("loesche","loesche");
187 add_action("rubrik","rubrik");
188 add_action("inhalt","inhalt");
189 add_action("rubriken","rubriken");
190 add_action("ReadNextUnread","nn");
191 add_action("Catchup","catchup");
192 add_action("Catchup","uebergeh");
193 add_action("Catchup","uebergehe");
194 add_action("Uncatchup","wiederhol");
195 add_action("Uncatchup","wiederhole");
196 add_action("Uncatchup","uncatchup");
197 add_action("Reply","antwort");
198 add_action("Reply","antworte");
199 add_action("Reply2","reply");
200 add_action("HelpPage","hilfe");
201 add_action("HelpPage","man");
202 add_action("Unsubscribe","unsubscribe");
203 add_action("Bestelle","bestell");
204 add_action("Bestelle","bestelle");
205 add_action("Subscribe","subscribe");
206 add_action("Subscribe","abonnier");
207 add_action("Subscribe","abonniere");
208 add_action("MoveMessage","verleg");
209 add_action("MoveMessage","verlege");
210 add_action("SetNNADWMSG","zeitungsmeldung");
211 add_action("Ignore","ignorier");
212 add_action("Ignore","ignoriere");
213 add_action("MailMessage","versende");
214 add_action("verbrennen","verbrenne");
215
216 if (IS_SEER(TP)) {
217 add_action("Mail","mail");
218 }
219 if (IS_LEARNER(TP)) {
220 add_action("SaveMessage","speicher");
221 add_action("SaveMessage","speichere");
222 add_action("ReadNextUnread","read"); /* NF Compatibility Special */
223 }
224 if (IS_ELDER(TP))
225 {
226 add_action("MoveTrash","trash");
227 }
228 init_rescue();
229}
230
231verbrennen(str) {
232 if (!str || !id(str)) return 0;
233 write("Du verbrennst Deine Zeitung mit groesstem Vergnuegen.\n");
234 say(TP->Name(WER)+" verbrennt "+
235 TP->QueryPossPronoun(FEMALE, WEN, SINGULAR)+" Zeitung in einem "
236 "Freudenfeuer.\n");
237 remove(1);
238 return 1;
239}
240
241// KillGroup - loescht eine nicht mehr benoetigte Rubrik aus der Liste.
242// Aufruf aus rubriken() und ReadNextUnread(), wenn die gueltige
243// Rubrikenliste sowieso schon abgerufen wurde.
244
245static KillGroup(name) { read_until=m_copy_delete(read_until,name); }
246
247/* RebuildGroupList() - tut doch nicht so, weil /secure/news anders arbeitet.
248 * Bleibt vorerst zum Nachschlagen.
249static RegisterGroup(name) { read_until[name]=1; }
250static RebuildGroupList() {
251 mixed groups;
252 if ((pointerp(groups=NEWSSERVER->GetGroups()))&&(sizeof(groups))) {
253 map(m_indices(read_until)-groups-SYSTEMGROUPS,#'KillGroup);
254 map(groups-m_indices(read_until),#'RegisterGroup);
255 }
256 TP->SetProp(P_READ_NEWS,read_until);
257}
258*/
259
260
261_set_autoloadobj(mixed arg) {
262
263 if (pointerp(arg) && sizeof(arg)>=2)
264 {
265 read_until=arg[1];
266 }
267 else {
268 if (TP)
269 read_until=((TP->QueryProp(P_READ_NEWS))||([]));
270 }
271
272 if (TP) TP->SetProp(P_READ_NEWS,read_until);
273}
274
275_query_autoloadobj() {
276 return 1;
277}
278
279static Mail(str) {
280 object mailer;
281 if (this_interactive()!=this_player()) return 0;
282 mailer=clone_object(MAILER);
283 mailer->SetOfficeName("mpa Kurierdienst");
284 mailer->do_mail( ((!str)||(str=="mail")) ? 0 : TP->_unparsed_args() );
285 return 1;
286}
287
288static varargs string Message2string(mixed msg,mixed messages,int flag,string group) {
289 // Aufrufe: (Nummer,Notes[,flag[,group]]) oder (Note,Notes[,flag[,group]])
290 // flag: M2S_VT100 : ggf ANSI-Codes verwenden
291 // M2S_REMOTE: Rubrik und Artikelnummer ausgeben (speichern, versenden)
292 // Achtung: Wenn flag&M2S_REMOTE, muss msg int sein
293 // group: Name der Rubrik, wenn nicht aktuelle Rubrik. Nur bei M2S_REMOTE
294
295 string txt,hs,s,*m,s2;
296 int i,hi,thisnr,ansiflag;
297
298 if (flag&M2S_REMOTE) txt="Rubrik: "+(group?group:GROUP)+", Artikel: "+
299 (intp(msg)?to_string(msg+1):"???")+" von "+sizeof(messages)+"\n";
300 else txt="";
301
302 if (intp(msg)) {
303 thisnr=msg;
304 msg=messages[msg];
305 } else thisnr=-1;
306 if (!msg) return 0;
307
308 ansiflag=(flag&M2S_VT100)&&(this_player()->QueryProp(P_TTY)!="dumb");
309
310 txt += (ansiflag?ANSI_BOLD:"")+ msg[M_TITLE]+(ansiflag?ANSI_NORMAL:"")+
311 " ("+msg[M_WRITER]+", "+
312 dtime(msg[M_TIME])[5..26]+"):\n";
313// if (geteuid(TP)=="sitopanaki") txt+="TID="+GetTID(msg)+"\n"; // Debug
314 if (!IS_STATUSLINE(msg[M_MESSAGE]))
315 return txt+"\n"+msg[M_MESSAGE];
316 m=explode(msg[M_MESSAGE],"\n");
317 while (IS_STATUSLINE(m[0])) {
318// txt+=m[0]+"\n"; // ###
319 if (sscanf(m[0],"%s rn=%s rt=%d rg=%s",hs,s,hi,hs)==4 ||
320 sscanf(m[0],"%s rn=%s rt=%d",hs,s,hi)==3)
321 {
322 int nr,h;
323 nr=-1;
324 if (pointerp(messages))
325 {
326 for (h=((thisnr>=0) ? thisnr-1 : sizeof(messages)-1);
327 (h>=0 && messages[h][M_TIME]>=hi);h--)
328 if (messages[h][M_TIME]==hi &&
329 lower_case(messages[h][M_WRITER])==lower_case(s))
330 nr=h;
331 }
332 txt+="[Bezug: Artikel "+((nr>=0) ? (nr+1) :
333 (hs==STATUSESCAPE||hs==(group?group:GROUP)?"(geloescht?)":"in "+hs))+
334 " von "+capitalize(s)+" vom "+dtime(hi)[5..26]+"]\n";
335 }
336 if (sscanf(m[0],"%s on=%s ot=%d og=%s",hs,s,hi,hs)==4) {
337 txt+="[Autor: "+s+", "+dtime(hi)[5..26]+", verlegt von "+hs+"]\n";
338 }
339 m=m[1..];
340 }
341 return txt+"\n"+implode(m,"\n");
342}
343
344static varargs lies(mixed str) {
345 mixed num;
346 mixed *messages;
347 int tid;
348
349 if (str=="?"||str=="-?") return
350 write("Syntax: lies <nr>\n"
351 " artikel <nr>\n"
352 "Siehe auch: nn\n"),1;
353
354 if (intp(str)) num=str;
355 if ((!num && (!str || str=="" || sscanf(str,"%d",num)!=1)) || num<=0) {
356 notify_fail("WELCHE Nachricht willst Du lesen?\n");
357 return 0;
358 }
359 if (!pointerp(messages=NEWSSERVER->GetNotes(GROUP)))
360 return notify_fail("Seltsam, die Rubrik '"+GROUP+
361 "' gibt es nicht mehr...\n"), 0;
362 num--;
363 if (sizeof(messages)<=num) {
364 notify_fail("So viele Artikel sind da nicht!\n");
365 return 0;
366 }
367
368 lasttitle=({messages[num][M_TITLE],messages[num][M_WRITER],
369 messages[num][M_TIME],GetTID(messages[num]),GROUP,num});
370 this_player()->More(Message2string(messages[num],messages,M2S_VT100));
371 if (this_player() && IS_LEARNER(this_player()))
372 this_player()->save_me(1);
373 return 1;
374}
375
376static varargs mixed GetGroupName(mixed g,mixed groups) {
377 /* Name einer Rubrik. g ist int oder string, enthaelt Name oder Nummer
378 (ab 1 numeriert) */
379 mixed i,expr,gg;
380 if (!g) return write("Du solltest schon die Rubrik angeben.\n"),0;
381 if (!groups) groups=NEWSSERVER->GetGroups();
382 if (intp(i=g) || sscanf(g,"%d",i)) {
383 if (i>0 && i<=sizeof(groups)) return groups[i-1];
384 write("Eine Rubrik mit der Nummer "+i+" gibt es leider nicht.\n");
385 return 0;
386 }
387 g=lower_case(g);
388 switch(g){
389 case ".": return GROUP;
390 case "+": return groups[(member(groups,GROUP)+1)%sizeof(groups)];
391 case "-":
392 return groups[(member(groups,GROUP)-1+sizeof(groups))%sizeof(groups)];
393 }
394
395 // Existiert die Rubrik genau so?
396 if (member(groups,g)>-1) return g;
397
398 g = regreplace(g,"[[\\]\\*()?]","",1);
399 // haerteres Kriterium: Alle Abschnitte angegeben
400 expr="^"+implode(explode(g,"."),"[^\\.]*\\.")+"[^\\.]*$";
401// write("REGEXP="+expr+"\n");
402 gg=regexp(groups,expr);
403 if (sizeof(gg)==1) return gg[0];
404
405 // weicheres Kriterium: Nicht alle Abschnitte angegeben
406 expr="^(.*\\.)*"+implode(explode(g,"."),".*\\.")+".*$";
407// write("REGEXP="+expr+"\n");
408 gg=regexp(groups,expr);
409
410 if (!sizeof(gg)) {
411 write("Eine Rubrik '"+g+"' gibt es hier leider nicht.\n");
412 return 0;
413 }
414
415 if (sizeof(gg)==1) return gg[0];
416
417 write(break_string("Die Rubrik "+g+" ist nicht eindeutig. Wahrscheinlich "
418 "meinst Du eine der folgenden: "+implode(gg,", ")+".\n",78));
419 return 0;
420}
421
422static rubrik(str)
423{
424 mixed *gruppen;
425 mixed news;
426 int anz,i;
427
428 if (str=="?"||str=="-?") return
429 write("Syntax: rubrik <rubrik>\n"
430 " wechselt die aktuelle Rubrik. Es wird die Nummer der Rubrik,\n"
431 " ihr Name oder jede eindeutige Abkuerzung akzeptiert.\n"),1;
432
433 if (!str || str==0) {
434 if (!pointerp(news=NEWSSERVER->GetNotes(GROUP))){
435 GROUP=DEFAULTGROUP;
436 if (!pointerp(news=NEWSSERVER->GetNotes(GROUP)))
437 return notify_fail("Seltsam, irgendwie geht hier einiges schief...\n"),0;
438 }
439 return write("Aktuelle Rubrik: "+GROUP+" ("+sizeof(news)+" Artikel).\n"),1;
440 }
441 str=GetGroupName(str);
442 if (!str) return 1;
443 GROUP=str;
444 news=NEWSSERVER->GetNotes(GROUP);
445 write(break_string("Ok, Du hast die Rubrik "+GROUP+" mit "+sizeof(news)+
446 " Artikel"+(sizeof(news)==1?"":"n")+" aufgeschlagen.\n",
447 78));
448 return 1;
449}
450
451LiesArtikel(str) {
452 string s1;
453 int i1;
454 if ( !str ) return 0;
455 if (sscanf(str,"rubrik %s",s1))
456 return rubrik(s1);
457 if (sscanf(str,"%d",i1))
458 return lies(to_int(i1));
459 if (sscanf(str,"artikel %s",s1))
460 return lies(s1);
461}
462
463
464/* Ueberpruefe, ob in Rubrik tote threads ignoriert werden. Tot bedeutet,
465 dass der letzte darin uebergangene Artikel bereits expired ist UND
466 keine Artikel aus diesem thread mehr vorhanden sind.
467 ACHTUNG: Es kann passieren, dass dazwischen noch ein neuer Artikel
468 dazugekommen ist.
469 Hier wird auf expired geprueft und ggf Variable deadTID gesetzt. Wird beim
470 Lesen mit nn ein Artikel mit dieser TID gefunden (passiert direkt hinter
471 Pruefung), wird deadTID wieder auf 0 gesetzt. Ist deadTID beim Umschalten
472 auf naechste Rubrik !=0, ist der thread tot.
473*/
474
475static int CheckThreads(string rubrik,int timeout) {
476 mixed tids;
477 int i;
478
479// deadTID=0;
480 tids=m_indices(read_until[IGNOREGROUP][rubrik]);
481 for (i=sizeof(tids)-1;i>=0&&!deadTID;i--)
482 if (read_until[IGNOREGROUP][rubrik][tids[i]]<timeout) deadTID=tids[i];
483 return 1;
484}
485
486static int rubriken(mixed arg)
487{
488 mixed *gruppen, *messages;
489 mixed news;
490 int anz,i,lasttime,timeout,foundone;
491 string s;
492
493 if (arg=="?"||arg=="-?") return
494 write("Syntax: rubriken listet alle Rubriken\n"
495 " rubriken neu nur Rubriken mit ungelesenen Artikeln\n"),1;
496
497 gruppen=NEWSSERVER->GetGroups();
498 map(m_indices(read_until)-gruppen-SYSTEMGROUPS,#'KillGroup); // ');
499 s="\nEs gibt zur Zeit ";
500 anz=sizeof(gruppen);
501 if (anz==0) {
502 write(s+"keine Rubriken (wie seltsam ...)\n");
503 return 1;
504 }
505 s+=anz+" Rubrik"+(anz==1 ? "" : "en")+".";
506 if (arg=="neu") s+="\nDavon enthalten neue Artikel:\n\n";
507 else s+="\n(* oder x: enthaelt neue Artikel, x oder -: abbestellt, "
508 ">: aktuelle Rubrik)\n\n";
509 for (i=0;i<anz;i++) {
510 timeout=read_until[gruppen[i]];
511 /* GetNewsTime lieferte leider manchmal was falsches :-( */
512 /* jetzt hoffentlich richtig? Wenn nicht, das if ausklammern */
513 if ( arg!="neu" || (lasttime=NEWSSERVER->GetNewsTime(gruppen[i])) > timeout) {
514 messages=NEWSSERVER->GetNotes(gruppen[i]);
515 if (!messages || !sizeof(messages)) lasttime=0;
516 else lasttime=messages[sizeof(messages)-1][M_TIME];
517 foundone=1;
518 }
519 if (arg!="neu" || (timeout>=0 && lasttime>abs(timeout)))
520 s+=sprintf("%s%s%3d\. %-39.39s: ",
521 ((gruppen[i]==GROUP)?">":" "),
522 ((lasttime>abs(timeout)) ? ((timeout<0) ? "x" : "*")
523 : ((timeout<0) ? "-" : " ") ),
524 i+1,gruppen[i])+
525 (lasttime ? sprintf("%3d Artikel (%s)\n",
526 sizeof(messages),
527 // ((sizeof(messages)==1) ? ". " : "en."),
528 dtime(lasttime)[5..12]+ctime(lasttime)[<2..]) :
529 " - leer -\n");
530 }
531 if (arg=="neu"&&!foundone) s+="Keine Rubrik enthaelt neue Artikel.\n";
532 this_player()->More(s);
533 return 1;
534}
535
536#define M_READNEXT 1
537#define M_LISTNEW 2
538#define M_LISTNEWGR 3
539#define M_READGR 4
540
541static ReadNextUnread(str)
542{
543 string *groups,group;
544 mixed *messages;
545 int curgr,curmsg,timeout,start,nrgroups,sog,mode;
546
547 if (str=="mail") return Mail(0); /* NF Compatibility Special */
548
549 if (str=="?"||str=="-?") return
550 write("Syntax: nn naechster neuer Artikel\n"
551 " nn <rubrik> in entspr. Rubrik, wenn da was neu ist\n"
552 " nn rubriken Liste der Rubriken mit neuen Artikeln\n"
553 " nn liste Liste der ungelesenen Artikel\n"),1;
554
555 groups=NEWSSERVER->GetGroups();
556 deadTID=0;
557 map(m_indices(read_until)-groups-SYSTEMGROUPS,#'KillGroup); //'
558 nrgroups=sizeof(groups);
559 if (str && str!="rubriken" && str!="liste"){
560 if (!group=GetGroupName(str)) return 1;
561 }
562 else
563 group=0;
564 if (group && (curgr=member(groups,group)+1)) {
565 --curgr;
566 if (curgr<0 || curgr>=sizeof(groups))
567 return notify_fail("Nee... so eine Rubrik gibts hier nicht.\n"),0;
568 GROUP=group;
569 start=curgr+1;
570 mode=M_READGR;
571 write("Rubrik "+(curgr+1)+": "+GROUP+"\n");
572 } else {
573 switch (str) {
574 case 0: mode=M_READNEXT; break;
575 case "liste": mode=M_LISTNEW; write("Du hast noch nicht gelesen:\n"); break;
576 case "rubriken": return rubriken("neu");
577 default:
578 notify_fail("\
579Diesen Parameter verstehe ich nicht. Entweder gar nichts, \"liste\"\n\
580\"rubriken\", oder Name bzw. Nummer einer Rubrik.\n");
581 return 0;
582 }
583 curgr=member(groups,GROUP);
584 start=curgr+nrgroups;
585 }
586 if (!pointerp(messages=NEWSSERVER->GetNotes(GROUP))){
587 GROUP=DEFAULTGROUP;
588 if (!pointerp(messages=NEWSSERVER->GetNotes(GROUP)))
589 return notify_fail("Seltsam, irgendwie geht hier einiges schief...\n"),0;
590 }
591 timeout=read_until[GROUP];
592 curmsg=0;
593 sog=sizeof(messages);
594 while (curgr<start) {
595 ++curmsg;
596 if (curmsg>sog) {
597 if (deadTID)
598 read_until[IGNOREGROUP][GROUP]=
599 m_copy_delete(read_until[IGNOREGROUP][GROUP],deadTID);
600 ++curgr;
601 deadTID=0;
602 if (mode!=M_READGR) {
603 GROUP=groups[curgr%nrgroups];
604 timeout=read_until[GROUP];
605 if (!timeout) read_until[GROUP]=1; // Nimm neue Gruppen in Liste auf
606 if (timeout<0 || timeout>=NEWSSERVER->GetNewsTime(GROUP)) {
607 sog=0; /* Ueberlistung: Gruppe hat nix neues oder */
608 curmsg=1; /* ist unsubscribed */
609 }
610 else {
611 messages=NEWSSERVER->GetNotes(GROUP);
612 curmsg=0;
613 sog=sizeof(messages);
614 }
615 }
616 } else {
617 if ((timeout>=0 || mode==M_READGR) && messages[curmsg-1][M_TIME] > abs(timeout)) {
618 if (pointerp(this_player()->QueryProp(P_IGNORE)) &&
619 member(this_player()->QueryProp(P_IGNORE),
620 lower_case(messages[curmsg-1][M_WRITER])+".news") != -1) {
621 printf("Uebergehe ignorierten Artikel %d von %s in Rubrik %s.\n",
622 curmsg,messages[curmsg-1][M_WRITER],GROUP);
623 read_until[GROUP]=messages[curmsg-1][M_TIME];
624 if (TP) TP->SetProp(P_READ_NEWS,read_until);
625 } else if
626 (read_until[IGNOREGROUP]&&
627 read_until[IGNOREGROUP][GROUP]&&
628 CheckThreads(GROUP,messages[0][M_TIME])&& /* Tote threads weg */
629 read_until[IGNOREGROUP][GROUP][GetTID(messages[curmsg-1])]) {
630 printf("Uebergehe Artikel %d aus ignoriertem Thread.\n",curmsg);
631 read_until[IGNOREGROUP][GROUP][GetTID(messages[curmsg-1])]=
632 messages[curmsg-1][M_TIME];
633 if (deadTID&&deadTID==GetTID(messages[curmsg-1])) deadTID=0;
634 read_until[GROUP]=messages[curmsg-1][M_TIME];
635 if (TP) TP->SetProp(P_READ_NEWS,read_until);
636 } else {
637 write("\nRubrik "+(curgr%nrgroups+1)+": "+GROUP+", Artikel: "+curmsg+" von "+sog+"\n");
638 if (mode==M_LISTNEW) {
639 write(sprintf(" %-45s [%-11s] %s\n",messages[curmsg-1][M_TITLE],
640 messages[curmsg-1][M_WRITER],
641 dtime(messages[curmsg-1][M_TIME])[5..16]));
642 } else { /* mode == M_READNEXT || mode==M_READGR */
643 if (timeout>=0) read_until[GROUP]=messages[curmsg-1][M_TIME];
644 else read_until[GROUP]=-messages[curmsg-1][M_TIME];
645 if (TP) TP->SetProp(P_READ_NEWS,read_until);
646 return (lies(""+curmsg));
647 }
648 }
649 }
650 /* sonst mach einfach garnix. Schleife laeuft weiter. */
651 }
652 }
653 switch(mode) {
654 case M_LISTNEW: return 1;
655 case M_READNEXT: write((read_until[NNADWMSG]||"Nix Neues auf der Welt.")
656 +"\n"); break;
657 case M_READGR: write("Nix Neues in dieser Rubrik.\n"); break;
658 }
659 return 1;
660}
661
662
663static SetNNADWMSG(str) {
664 if (str=="?"||str=="-?") return
665 write("Syntax: zeitungsmeldung <neue Meldung> setzt Meldung\n"
666 " zeitungsmeldung loescht Meldung\n"),1;
667 if (!read_until[NNADWMSG]) {
668 write("Du hast zur Zeit keine eigene NNADW-Meldung definiert.\n");
669 if (!str) return 1;
670 }
671 else write("Deine alte NNADW-Meldung war:\n"+read_until[NNADWMSG]+"\n");
672 if (!str) {
673 read_until=m_copy_delete(read_until,NNADWMSG);
674 write("Meldung ist geloescht, es gilt wieder die Standardmeldung.\n");
675 } else {
676 read_until[NNADWMSG]=this_player()->_unparsed_args();
677 write("Deine neue Meldung lautet jetzt:\n"+read_until[NNADWMSG]+"\n");
678 }
679 if (TP) TP->SetProp(P_READ_NEWS,read_until);
680 return 1;
681}
682
683varargs int InterpretTime(mixed a,int flag) {
684 // string oder string *
685 // akzeptiert folgende Formate:
686 // dd.mm.jj (Rueckgabe: 0:00 des entsprechenden Tages)
687 // vor [<anz> d|tagen] [<anz> h|stunden] [<anz> m|minuten]
688 // flag=1: "inklusive": bei dd.mm.jj-Format 23:59:59 statt 0:00 Uhr
689
690 int i,j,k,t,nrargs;
691 string s;
692 if (stringp(a)) a=explode(a," ");
693
694// printf("%O\n",a);
695
696 if ((nrargs=sscanf(a[0],"%d.%d.%d",i,j,k))==3 ||
697 (nrargs=sscanf(a[0],"%d.%d.",i,j))==2) {
698 // Datum -> Zeit: Funktioniert im Zeitraum 1973 - ca. 2090
699 // in Zeitzonen mit ganzen Stunden ggue Rechneruhr.
700 if (nrargs==2)
701 k=70+time()/31536000;
702 if (k<70) k+=100;
703 if (k>1970) k-=1900;
704 if (k<70||k>150) return
705 write("Unzulaessiges Jahr (erlaubt: 70-heute).\n"),0;
706 t=(k-70)*31536000;
707
708 if (i<1||i>31) return write("Unzulaessiger Tag (erlaubt: 1-31).\n"),0;
709 if (j<1||j>12) return write("Unzulaessiger Monat (erlaubt: 1-12).\n"),0;
710// printf("%d.%d.%d\n",i,j,k);
711 s=ctime(t);
712 if ((j>2) && !(k%4)) t+=86400; // Schaltjahrkorrektur fuer Monate>=3
713 t+=({ 0, 2678400, 5097600, 7776000,
714 10368000, 13046400, 15638400, 18316800,
715 20995200, 23587200, 26265600, 28857600})[j-1];
716 t+=86400*(i-1);
717 t+=86400*(32-to_int(s[8..9])); // Schaltjahrkorrektur
718 t-=3600*to_int(s[11..12]); // Zeitzonenkorrektur
719 t-=3600*to_int(ctime(t)[11..12]); // Sommerzeitkorrektur
720// write("Kontrolle: "+dtime(t)+"\n");
721 if (nrargs==2 && t>time()) t-=31536000;
722 return (flag?t+86399:t);
723 }
724
725 t=0;
726 if (a[0]=="vor") for (i=sizeof(a)-1;i>0;i--) {
727 switch (a[i]) {
728 case "m":
729 case "minuten":
730 case "min":
731 case "minute":
732 t+=60*to_int(a[i-1]);
733 break;
734 case "h":
735 case "stunde":
736 case "stunden":
737 case "s":
738 t+=3600*to_int(a[i-1]);
739 break;
740 case "d":
741 case "tag":
742 case "tage":
743 case "t":
744 t+=86400*to_int(a[i-1]);
745 break;
746 default:
747 if (!to_int(a[i]))
748 write("Argumentfehler: Kann nichts mit '"+a[i]+"' anfangen.\n");
749 }
750 return time()-t;
751 }
752 else return write("Argumentfehler.\n"),0;
753}
754
755static Catchup(string str)
756{
757 int welche,zeit,i;
758 string gr;
759 mixed groups,news,args;
760
761 if (!pointerp(NEWSSERVER->GetNotes(GROUP)))
762 return notify_fail("Seltsam, die Rubrik '"+GROUP+
763 "' gibt es nicht mehr...\n"), 0;
764
765 str=this_player()->_unparsed_args(); // wg. Datum
766 if (str) str=lower_case(str);
767 else str=GROUP; // default: aktuelle Rubrik komplett.
768
769 if (str=="?"|| str=="-?") return CatchupSyntax();
770
771 // uebergehe Antworten (Thread ignorieren)
772 if (str&&(str[0..6]=="antwort"||str=="thread")) {
773 if (!pointerp(lasttitle)) return
774 write("Du hast bisher noch keinen Artikel gelesen, damit kann ich nicht wissen,\nwelchen Thread du uebergehen willst.\n"),1;
775 if (!read_until[IGNOREGROUP]) read_until[IGNOREGROUP]=([]);
776 if (!read_until[IGNOREGROUP][GROUP]) read_until[IGNOREGROUP][GROUP]=([]);
777 if (read_until[IGNOREGROUP][GROUP][lasttitle[3]]) {
778 read_until[IGNOREGROUP][GROUP]=m_copy_delete(read_until[IGNOREGROUP][GROUP],lasttitle[3]);
779 write("Dieser Thread wird jetzt nicht mehr uebergangen.\n");
780 } else {
781 read_until[IGNOREGROUP][GROUP][lasttitle[3]]=lasttitle[2];
782 write("Dieser Thread wird ab sofort uebergangen.\nFalls das ein Irrtum war, wiederhole den Befehl augenblicklich.\n");
783 }
784 if (TP) TP->SetProp(P_READ_NEWS,read_until);
785 return 1;
786 }
787
788 groups=NEWSSERVER->GetGroups();
789
790 args=explode(str," ");
791
792 // Uebergehe alles
793
794 if (args[0]=="alle" || args[0]=="alles" || args[0]=="all") {
795 if (sizeof(args)<=1) zeit=time()-1;
796 else if (args[1]!="bis") return CatchupSyntax();
797 else if (sizeof(args)<3) return CatchupSyntax();
798
799 else zeit=InterpretTime(args[2..],1);
800 if (zeit>time()) zeit=time()-1;
801 write("Uebergehe alle Rubriken bis "+dtime(zeit)+".\n");
802 for (welche=0;welche<sizeof(groups);++welche) {
803 gr=groups[welche];
804// zeit=NEWSSERVER->GetNewsTime(gr);
805 if (abs(read_until[gr])<zeit)
806 read_until[gr]=(read_until[gr]>=0)?zeit:-zeit;
807 if (TP) TP->SetProp(P_READ_NEWS,read_until);
808 }
809 return 1;
810 }
811
812 // Anzahl Artikel
813
814 if (sizeof(args)>=2 && args[1]=="artikel") {
815 if (!to_int(args[0])) return CatchupSyntax();
816 news=NEWSSERVER->GetNotes(GROUP);
817 for (i=sizeof(news)-1;i>=0&&news[i][M_TIME]>read_until[GROUP];i--);
818 welche=i+to_int(args[0]);
819 if (welche>=sizeof(news)) welche=sizeof(news)-1;
820 write("Uebergehe die naechsten "+(welche-i)+" Artikel in Rubrik "+
821 GROUP+"\n.");
822 if (welche>=0) {
823 zeit=news[welche][M_TIME];
824 read_until[GROUP]=(read_until[GROUP]>=0)?zeit:-zeit;
825 if (TP) TP->SetProp(P_READ_NEWS,read_until);
826 }
827 return 1;
828 }
829
830 // einzelne Rubrik.
831
832 if (!(gr=GetGroupName(args[0]))) return 1;
833 news=NEWSSERVER->GetNotes(gr);
834 if (!sizeof(news)) {
835 write("Rubrik "+gr+" ist leer.\n");
836 return 1;
837 }
838// zeit=news[sizeof(news)-1][M_TIME];
839 if (sizeof(args)<=1)
840 zeit=time();
841 else
842 if (args[1]!="bis") return CatchupSyntax();
843 else
844 zeit=InterpretTime(args[2..],1);
845 if (zeit>time()) zeit=time();
846 read_until[gr]=zeit;
847 if (TP) TP->SetProp(P_READ_NEWS,read_until);
848 write("Uebergehe "+gr+" bis "+dtime(zeit)+",\nletzter Artikel war vom "+
849 dtime(NEWSSERVER->GetNewsTime(gr))+"\n");
850 return 1;
851}
852
853
854static Ignore(str) {
855 if (str=="thread"||str=="antworten") return Catchup(str);
856 return 0;
857}
858
859static CatchupSyntax() {
860 write("Syntax des Befehls uebergehe (oder catchup):\n"
861 " uebergehe [rubrik] (default: aktuelle Rubrik)\n"
862 " uebergehe alles (in allen Rubriken)\n"
863 " uebergehe <anz> artikel (in akt. Rubrik)\n"
864 " uebergehe [rubrik]|alles bis <tag>.<monat>.[<jahr>]\n"
865 " uebergehe [rubrik]|alles bis vor <zeit> wobei\n"
866 " <zeit> = [<n> d|tage] [<n> h|stunden] [<n> m|min|minuten]\n"
867 " uebergehe thread|antworten (entspr. 'ignoriere thread')\n");
868
869 return 1;
870}
871
872
873static int UncatchupSyntax()
874{
875 notify_fail(
876 "Syntax: wiederhole <anz> [artikel]\n"
877 " wiederhole [ab vor] [<anz> m|minute[n]] [<anz> h|stunde[n]] [<anz> d|tag[e]]\n"
878 " wiederhole ab tag.monat[.jahr]\n"
879 " wiederhole alles\n"
880 "Der wiederhole- oder uncatchup-Befehl bezieht sich immer auf die aktuelle\n"
881 "Rubrik und markiert die angegebenen Artikel wieder als ungelesen.\n"
882 "Zeiten (2. Syntax) sind rueckwaerts ab aktueller Uhrzeit gerechnet.\n"),0;
883 return 0;
884}
885
886
887static Uncatchup(string str)
888{
889 mixed args;
890 int i,zeit;
891 int mode; // 0 = nix, 1=Anzahl Artikel, 2=Zeit, 3=alles
892
893 str=this_player()->_unparsed_args(); // wg. Datum
894 if ( !TP || !str || !stringp(str) || str=="?" || str=="-?" )
895 return UncatchupSyntax();
896
897 if (!pointerp(NEWSSERVER->GetNotes(GROUP)))
898 return notify_fail("Seltsam, die Rubrik '"+GROUP+
899 "' gibt es nicht mehr...\n"), 0;
900
901 args=({""})+explode(lower_case(str)," ");
902 if (args[1]=="ab") {
903 mode=2;
904 if (sizeof(args)<3)
905 return UncatchupSyntax();
906 zeit=InterpretTime(args[2..]);
907 } else {
908 zeit=time();
909 for (i=sizeof(args)-1;i>0;i--) {
910 switch(args[i]){
911 case "alles":
912 case "alle":
913 case "all":
914 if (mode&&mode!=3) return
915 notify_fail("Bitte nur Zeit ODER alles ODER Anzahl angeben!\n"),0;
916 mode=3;
917 break;
918 case "minuten":
919 case "minute":
920 case "m":
921 case "stunden":
922 case "stunde":
923 case "h":
924 case "tage":
925 case "tag":
926 case "d":
927 if (mode&&mode!=2) return
928 notify_fail("Bitte nur Zeit/Datum ODER alles ODER "
929 "Anzahl angeben!\n"),0;
930 mode=2;
931 zeit-=(((args[i][0]=='m') ? 60 :
932 ((args[i][0]=='s' || args[i][0]=='h') ? 3600 : 86400))
933 *to_int(args[i-1]));
934 i--;
935 break;
936 case "artikel":
937 if (mode&&mode!=1) return
938 notify_fail("Bitte nur Zeit/Datum ODER alles ODER "
939 "Anzahl angeben!\n"),0;
940 mode=1;
941 zeit=to_int(args[i-1]);
942 i--;
943 break;
944 case "ab":
945 return
946 notify_fail("Bitte nur Zeit/Datum ODER alles ODER "
947 "Anzahl angeben!\n"),0;
948 default:
949 if (!to_int(args[i]))
950 return notify_fail("Unbekanntes Argument '"+args[i]+
951 "'! Aktion abgebrochen.\n"),0;
952 if (mode&&mode!=1) return
953 notify_fail("Bitte nur Zeit/Datum ODER alles ODER "
954 "Anzahl angeben!\n"),0;
955 mode=1;
956 zeit=to_int(args[i]);
957 }
958 }
959 }
960
961 switch(mode){
962 case 0:
963 return notify_fail("Gib bitte irgendeine Einheit an "
964 "(Hilfe mit wiederhole -?)!\n");
965 case 2:
966 read_until[GROUP]=(read_until[GROUP]>=0)?zeit:-zeit;
967 write(break_string("Markiere alle Artikel in Rubrik "+GROUP+
968 " seit "+dtime(zeit)+" als ungelesen.\n",78));
969 break;
970 case 3:
971 read_until[GROUP]=(read_until[GROUP]>=0?1:-1);
972 write("Markiere die komplette Rubrik "+GROUP+" als ungelesen.\n");
973 break;
974 case 1:
975 write(break_string("Markiere die letzten "+zeit+
976 " gelesenen Artikel in Rubrik "+GROUP+" als ungelesen.\n",78));
977 { int h; mixed notes;
978 notes=NEWSSERVER->GetNotes(GROUP);
979 h=sizeof(notes)-1;
980 while ( (h>=0) && (abs(read_until[GROUP]) < notes[h][M_TIME]) ) {
981 h--;
982 }
983 if (h==-1||h<zeit)
984 read_until[GROUP]=
985 (read_until[GROUP]>=0)?1:-1;
986 else
987 read_until[GROUP]=(
988 (read_until[GROUP]>=0)?notes[h-zeit][M_TIME]
989 :-notes[h-zeit][M_TIME]);
990 }
991 }
992 write("Ok. Du kannst die als ungelesen markierten Artikel "
993 "mit nn nochmal lesen.\n");
994
995 if (TP) TP->SetProp(P_READ_NEWS,read_until);
996 return 1;
997}
998
999
1000QueryRead() {
1001 return read_until;
1002}
1003
1004static CatchNewsError(int err,string text4minus3) {
1005 switch (err) {
1006 case 1: return 1;
1007 case -1: write("Du darfst in dieser Rubrik nicht schreiben!\n"); return 0;
1008 case -2: write("Die Rubrik gibt es nicht mehr, sehr seltsam...\n"); return 0;
1009 case -3: write(text4minus3+"\n"); return 0;
1010 default: write("Interner Fehler "+err+", Erzmagier verstaendigen!\n"); return 0;
1011 }
1012}
1013
1014static varargs schreib(str,pretext,called_by_itself,statuslines) {
1015 int err;
1016
1017 if (str=="?"||str=="-?") {
1018 write("Syntax: schreib <Titel>\n"
1019 " beginnt einen neuen Artikel in der Zeitung.\n");
1020 return 1;
1021 }
1022
1023 if (!this_interactive() || !this_interactive()->query_real_name()) return 0;
1024 if (!called_by_itself && extern_call() && !pretext)
1025 str=this_interactive()->_unparsed_args()||"";
1026 if (called_by_itself && str=="~q") {
1027 write("Abgebrochen.\n");
1028 return 1;
1029 }
1030 if (!CatchNewsError(
1031 NEWSSERVER->AskAllowedWrite(GROUP),
1032 "Diese Rubrik ist leider schon randvoll!")) return 1;
1033 if (!called_by_itself)
1034 write("Neuer Artikel in Rubrik "+GROUP+":\n");
1035 if (!str || str=="" || str=="artikel") {
1036 input_to("schreib", INPUT_PROMPT, "Titel des Artikels: ", pretext,1);
1037 return 1;
1038 }
1039 // writer=this_interactive()->query_real_name();
1040 message=allocate(6);
1041 message[M_BOARD]=GROUP;
1042 message[M_TITLE]=killctrl(str);
1043 message[M_MESSAGE]=statuslines;
1044 write("Titel ist: "+str+".\n\
1045Gib jetzt Deinen Text ein,\n\
1046** oder . wenn Du fertig bist, ~q zum Abbrechen, ~h fuer eine Hilfsseite.\n");
1047 nedit("PostNote",pretext);
1048 return 1;
1049}
1050
1051static varargs Reply(string str,string newtitle) {
1052 mixed dummy,replytitle,s;
1053 int nr;
1054
1055 if ((dummy=(str||newtitle))=="?"||dummy=="-?") {
1056 write("Der Antworte-Befehl ist doppelt belegt.\n"
1057 "1. (Zeitung): Schreibe Antwort auf einen Artikel in der Zeitung.\n"
1058 " Syntax: antworte\n"
1059 " antworte auf artikel <nr> [neuer Titel]\n"
1060 " reply [auf artikel <nr> | to note <nr>] [neuer Titel]\n"
1061 "2. aehnlich 'sage':\n"
1062 " Du tippst zum Beispiel:\n"
1063 " antworte ja, das weiss ich\n"
1064 " Alle Spieler im Raum sehen dann:\n"
1065 " <Dein Name> antwortet: ja, das weiss ich.\n"
1066 "Bitte beachte, dass jede Syntax, die auf den antworte-Befehl der "
1067 "Zeitung\npasst, auch von der Zeitung ausgewertet wird.\n");
1068 return 1;
1069 }
1070
1071 if (str&&
1072 ((sscanf(lower_case(str),"auf artikel %d",dummy)==1 &&
1073 str=this_player()->_unparsed_args()[12..])||
1074 (sscanf(lower_case(str),"to note %d",dummy)==1 &&
1075 str=this_player()->_unparsed_args()[8..]))) {
1076 mixed notes;
1077 notes=NEWSSERVER->GetNotes(GROUP);
1078 if (dummy<1||dummy>sizeof(notes))
1079 return write("Einen Artikel mit der Nummer "+dummy+
1080 " gibt es in dieser Rubrik nicht.\n"),1;
1081 dummy--;
1082 replytitle=({notes[dummy][M_TITLE],notes[dummy][M_WRITER],
1083 notes[dummy][M_TIME],GetTID(notes[dummy]),GROUP});
1084 DEBUGVAR(str);
1085 if (!newtitle&&str&&sizeof(str)&&sscanf(str,"%d %s",dummy,str)==2)
1086 newtitle=str;
1087 }
1088 else if (!str||!sizeof(str)) {
1089 if (!lasttitle) return
1090 write("Du hast noch gar nichts gelesen, worauf Du "
1091 "antworten koenntest.\n"),1;
1092 replytitle=lasttitle;
1093 }
1094 else return 0;
1095
1096// return ComposeReply(replytitle);
1097//}
1098//
1099//
1100//ComposeReply(mixed replytitle) {
1101
1102 if (!newtitle) {
1103 if (replytitle[0][0..7]=="Re: Re: ") newtitle="Re^3: "+replytitle[0][8..];
1104 else if (sscanf(replytitle[0],"Re^%d: %s",nr,newtitle))
1105 newtitle="Re^"+(nr+1)+": "+newtitle;
1106 else newtitle="Re: "+replytitle[0];
1107 }
1108 return schreib(newtitle,0,0,
1109 STATUSESCAPE+" rn="+replytitle[LAST_WRITER]+
1110 " rt="+replytitle[LAST_TIME]+
1111 " rg="+replytitle[LAST_GROUP]+"\n"+
1112 STATUSESCAPE+" tid="+replytitle[LAST_TID]+"\n");
1113}
1114
1115static Reply2(str) {
1116 str = this_player()->_unparsed_args();
1117 if (!str||str[0..11]=="auf artikel "||str[0..7]=="to note ")
1118 return Reply(str);
1119 return Reply(0,str);
1120}
1121
1122static void InformPlayers(string group,string player,string text)
1123{
1124 object *players;
1125 int i;
1126 mixed data;
1127 string ig;
1128
1129 players=users();
1130 ig=lower_case(player)+".news";
1131 for (i=sizeof(players)-1;i>=0;i--) {
1132 data=players[i]->QueryProp(P_WAITFOR);
1133 if (pointerp(data)&&(member(data,"Mpa")>-1)) {
1134 data=players[i]->QueryProp(P_READ_NEWS);
1135 if (mappingp(data)&&(data[group]>0)) {
1136 data=players[i]->QueryProp(P_IGNORE);
1137 if ((!pointerp(data))||(member(data,ig)==-1))
1138 tell_object(players[i],text);
1139 }
1140 }
1141 }
1142}
1143
1144static PostNote(text) {
1145 int err;
1146 string sig;
1147
1148 if (!text) {
1149 write("Abbruch! Artikel landet im Reisswolf.\n");
1150 return 1;
1151 }
1152 if (!sizeof(old_explode(text,"\n")-
1153 ({"q","quit"," **","** ","ende","","exit"," "})
1154 ) )
1155 return write("\
1156ACHTUNG: Wolltest Du wirklich einen Artikel ohne Inhalt in die mpa setzen?\n\
1157Artikel ohne erkennbaren Inhalt werden NICHT veroeffentlicht. Bitte ueber-\n\
1158pruef Deine Syntax, falls Du keinen Artikel schreiben wolltest, oder schreib\n\
1159auch ein bisschen Text!\n\
1160Artikel landet im Reisswolf.\n"),1;
1161 if (!message[M_MESSAGE])
1162 message[M_MESSAGE] = text;
1163 else
1164 message[M_MESSAGE]+=text;
1165 if (sig=read_file("/players/"+geteuid(this_interactive())+"/.signature"))
1166 message[M_MESSAGE]+=sig;
1167 if (!CatchNewsError(NEWSSERVER->WriteNote(message),
1168 "Diese Rubrik ist voll. Mist, da war jemand schneller...")) {
1169 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");
1170 return 0;
1171 }
1172 write("OK, Artikel ist veroeffentlicht.\n");
1173 say(capitalize(TP->name())+
1174 " hat einen Artikel in der Zeitung veroeffentlicht.\n");
1175 if (geteuid(TP)!="sitopanaki")
1176 InformPlayers(message[M_BOARD],geteuid(this_interactive()),
1177 "* MPA: Neuer Artikel von "+
1178 capitalize(geteuid(this_interactive()))+
1179 " in Rubrik \""+message[M_BOARD]+"\".\n");
1180 message=0; /* Platz sparen! */
1181 return 1;
1182}
1183
1184
1185//static // allowing aliasing *Rumata* 5/8/96
1186inhalt(str) {
1187 int i,endflag,timeout;
1188 string *gruppen,s,txt,suche;
1189 mixed messages;
1190
1191 if (str=="?"||str=="-?") return
1192 write("Syntax: inhalt [<rubrik>] [ende] [suche <text>]\n"),1;
1193
1194 str=(!str)?({}):explode(str," ");
1195
1196 if (sizeof(str) && (str[0]=="neu" || str[0]=="neues") )
1197 return ReadNextUnread("liste"),1;
1198
1199 if (endflag=member(str,"ende")+1) str-=({"ende"});
1200 if (((i=member(str,"suche")) != -1) && (sizeof(str) > i)) {
1201 suche=lower_case(implode(str[i+1..]," "));
1202 str=str[0..i-1];
1203 }
1204 else
1205 suche=0;
1206 if (!sizeof(str)) {
1207 str=GROUP;
1208 if (!pointerp(messages=NEWSSERVER->GetNotes(str))){
1209 str=GROUP=DEFAULTGROUP;
1210 if (!pointerp(messages=NEWSSERVER->GetNotes(str)))
1211 return notify_fail("Seltsam, irgendwie geht hier einiges schief...\n"),0;
1212 }
1213 }
1214 else {
1215 str=GetGroupName(str[0]);
1216 if (!str) return 1;
1217 messages=NEWSSERVER->GetNotes(str);
1218 }
1219 timeout=abs(read_until[str]);
1220 s="Inhalt der Rubrik "+str+":\n\n";
1221 if (!pointerp(messages) || !sizeof(messages))
1222 return
1223 write(s+"Zur Zeit befinden sich keine Artikel in dieser Rubrik.\n"),1;
1224 if (suche)
1225 s+="Suche nach '"+suche+"' in der Rubrik ergab folgende Treffer:\n\n";
1226 else
1227 if (sizeof(messages)==1)
1228 s+="Zur Zeit befindet sich ein Artikel in der Rubrik:\n\n";
1229 else
1230 s+="Zur Zeit befinden sich "+sizeof(messages)+
1231 " Artikel in der Rubrik:\n\n";
1232 if (endflag&&(sizeof(messages)>16)&&
1233 messages[sizeof(messages)-16][M_TIME]>=timeout) timeout=-1;
1234 for (i=(endflag?(((endflag=sizeof(messages)-15)<0)?0:endflag):0);
1235 i<sizeof(messages);i++)
1236 {
1237 txt=sprintf("%2d.%s%-48s%4d (%-11s) %s\n",i+1,
1238 (((timeout>=0) && timeout<messages[i][M_TIME] )?
1239 ( (timeout=-1),"*"):" "),messages[i][M_TITLE],
1240 sizeof(explode(messages[i][M_MESSAGE],"\n")),
1241 messages[i][M_WRITER],
1242 dtime(messages[i][M_TIME])[5..11]);
1243 if (!suche || (strstr(lower_case(txt), suche) != -1))
1244 s+=txt;
1245 }
1246 if (endflag) write(s);
1247 else this_player()->More(s);
1248 return 1;
1249}
1250
1251
1252static artikel(str) {
1253 return lies(str);
1254}
1255
1256
1257static loesche(str) {
1258 int num;
1259 mixed *messages;
1260
1261 if (str=="?"||str=="-?") return
1262 write("Syntax: loesche artikel <nr>\n"
1263 " (bezieht sich immer auf die aktuelle Rubrik.\n"),1;
1264
1265 if (!str || sscanf(str,"artikel %d",num)!=1 || num<=0)
1266 return notify_fail("WELCHEN Artikel willst Du loeschen ?\n"),0;
1267 num--;
1268 messages=(NEWSSERVER->GetNotes(GROUP));
1269 if (sizeof(messages)<=num) return
1270 notify_fail("So viele Artikel sind da nicht!\n"),0;
1271
1272 write("Rubrik "+GROUP+", Artikel "+(num+1)+
1273 " von "+capitalize(messages[num][M_WRITER])+
1274 " vom "+dtime(messages[num][M_TIME])[5..26]+
1275 ",\nTitel: "+messages[num][M_TITLE]+",\n\n");
1276
1277 /* (ueberfluessige Abfrage, macht schon /secure/news)
1278 if (!IS_LEARNER(TI) && lower_case(messages[num][M_WRITER])!=geteuid(TI))
1279 return
1280 write("Nicht geloescht - du darfst nur eigene Artikel loeschen.\n"),1;
1281 */
1282
1283 switch (NEWSSERVER->RemoveNote(GROUP, num)){
1284 case 1: write("Artikel ist geloescht.\n");
1285 say(this_player()->name()+" loescht einen Artikel aus der Zeitung.\n");
1286 return 1;
1287 case -1: write("Diesen Artikel darfst Du nicht loeschen.\n");
1288 say(this_player()->name()+" versucht vergeblich, einen Artikel zu loeschen.\n");
1289 return 1;
1290 case -3: write("So viele Artikel sind da nicht !\n");
1291 return 1;
1292 default: write("Interner Fehler. Bitte Erzmagier verstaendigen !\n");
1293 return 1;
1294 }
1295}
1296
1297// Low-level Funktion zum Abonnieren/Abbestellen von Rubriken
1298// bestellen==0 -> abbestellen, bestellen!=0 -> bestellen
1299// Rueckgabe: 0, wenn der gewuenschte Zustand schon eingestellt war, sonst 1
1300private int _subscribe(string groupname, int bestellen) {
1301
1302 int timeout = read_until[groupname];
1303 // gar nicht abonniert/abbestellt?
1304 if (!bestellen && timeout < 0)
1305 return 0;
1306 else if (bestellen && timeout > 0)
1307 return 0;
1308
1309 // wenn noch kein timeout, erstmal auf 1 setzen
1310 timeout ||= 1;
1311
1312 // -1 fuer abbestellen, +1 fuer bestellen
1313 if (bestellen)
1314 read_until[groupname] = abs(timeout);
1315 else
1316 read_until[groupname] = -timeout;
1317
1318 if (environment())
1319 environment()->SetProp(P_READ_NEWS, read_until);
1320
1321 return 1;
1322}
1323
1324static Unsubscribe(str) {
1325 int timeout;
1326 if (str=="?"||str=="-?") return
1327 write("Syntax: unsubscribe <rubrik>"
1328 " oder: bestelle <rubrik> ab\n"),1;
1329 str=GetGroupName(str);
1330 if (!str) return 1;
1331 if (!_subscribe(str,0)) {
1332 notify_fail("Die Rubrik hast Du gar nicht abonniert!\n");
1333 return 0;
1334 }
1335 else {
1336 write("Rubrik "+str+" abbestellt.\n");
1337 }
1338 return 1;
1339}
1340
1341
1342static Bestelle(str) { /* ab ! */
1343 if (!str || !sscanf(str,"%s ab",str)) return _notify_fail(
1344 "Die Syntax ist: 'bestelle <rubrik> ab', "
1345 "oder meinst Du 'abonniere'?\n"),0;
1346 return Unsubscribe(str);
1347}
1348
1349static Subscribe(str) {
1350 int timeout;
1351 if (str=="?"||str=="-?") return
1352 write("Syntax: abonniere <rubrik>\n"
1353 " oder: subscribe <rubrik>\n"),1;
1354 str=GetGroupName(str);
1355 if (!str) return 1;
1356 if (!_subscribe(str,1)) {
1357 notify_fail("Die Rubrik hast Du doch schon abonniert!\n");
1358 return 0;
1359 }
1360 else {
1361 write("Rubrik "+str+" abonniert.\n");
1362 }
1363 return 1;
1364}
1365
1366// Legt die anfaenglichen Abonnements eines Neulesers fest und bestellt alle
1367// anderen ab.
1368private void InitialSubscriptions() {
1369 // alle abbestellen. ;-)
1370 // Alternative: fuer alle _subscribe(,0) rufen
1371 if (!query_once_interactive(environment()))
1372 return;
1373 string *gruppen = NEWSSERVER->GetGroups();
1374 int *vals = allocate(sizeof(gruppen),-1);
1375 read_until = mkmapping(gruppen,vals);
1376
1377 // jetzt die vorausgewaehlten bestellen
1378 foreach(string gruppe : INITIAL_SUBSCRIPTIONS) {
1379 if (member(gruppen, gruppe) > -1)
1380 _subscribe(gruppe,1);
1381 }
1382 // und ggf. noch die eigene Gildenrubrik
1383 string gilde = environment()->QueryProp(P_GUILD);
1384 if (stringp(gilde)
1385 && member(gruppen, "gilden."+gilde) > -1)
1386 _subscribe("gilden."+gilde,1);
1387
1388 environment()->SetProp(P_READ_NEWS, read_until);
1389}
1390
1391static MoveMessage(str) {
1392 int num,i;
1393 mixed msg/*,expl*/;
1394 string gr;
1395 if (str=="?"||str=="-?") return
1396 write("Syntax: verlege artikel <nr> nach <rubrik>\n"
1397 " Artikel und Rubrik muessen explizit angegeben werden.\n"),1;
1398 if (!str || sscanf(str,"artikel %d nach %s",num,gr)!=2) return (int)notify_fail(
1399 "verlege artikel <nr> nach <rubrik>, oder was?\n");
1400 if (!(gr=GetGroupName(gr))) return 1;
1401 if (!(CatchNewsError(NEWSSERVER->AskAllowedWrite(gr),"Die Rubrik ist leider voll.\n"))) return 1;
1402
1403 if (!pointerp(msg=NEWSSERVER->GetNotes(GROUP)))
1404 return notify_fail("Seltsam, die Rubrik '"+GROUP+
1405 "' gibt es nicht mehr...\n"), 0;
1406
1407 num--;
1408 if (sizeof(msg)<=num) return
1409 notify_fail("So viele Nachrichten sind da nicht !\n"),0;
1410 msg=msg[num];
1411 if (geteuid(TI) != lower_case(msg[M_WRITER])) {
1412 if (!IS_LEARNER(TI)) return
1413 write("Du darfst nur Deine eigenen Artikel verlegen.\n"),1;
1414 write("WARNUNG: Das ist nicht Dein eigener Artikel!\n");
1415 }
1416 // return (int)notify_fail("Man darf zur Zeit nur eigene Artikel verlegen.\n");
1417 if (!CatchNewsError(NEWSSERVER->RemoveNote(GROUP,num),"Dieser Fehler kann eigentlich nicht auftreten"))
1418 write("Warnung! Konnte Artikel an alter Position nicht loeschen.\n");
1419 else write("Artikel von Rubrik "+GROUP+" entfernt.\n");
1420
1421 msg[M_MESSAGE]=
1422 sprintf("%s on=%s ot=%d og=%s\n",
1423 STATUSESCAPE,msg[M_WRITER],msg[M_TIME],msg[M_BOARD])
1424 +msg[M_MESSAGE];
1425
1426/*
1427 expl=explode(msg[M_MESSAGE],"\n");
1428 for (i=0;(IS_STATUSLINE(expl[i][0..2]));i++);
1429 msg[M_MESSAGE]=( (i) ? implode(expl[0..i-1],"\n")+"\n" : "" ) +
1430 "[Verlegt von "+msg[M_BOARD]+", "+msg[M_WRITER]+", "+
1431 dtime(msg[M_TIME])[5..26]+"]:\n"+
1432 implode(expl[i..],"\n")+"\n";
1433*/
1434
1435 msg[M_BOARD]=gr;
1436 NEWSSERVER->WriteNote(msg);
1437 write("Artikel nach Rubrik "+gr+" verlegt.\n");
1438 return 1;
1439}
1440
1441static MoveTrash()
1442{
1443 if (!pointerp(lasttitle)||sizeof(lasttitle)<LAST_SIZEOF) return
1444 write("Was denn bitte? Du hast noch gar nichts gelesen!\n"),1;
1445 if (lasttitle[LAST_GROUP]!=GROUP) return
1446 write("Nix gibts! Du hast die Rubrik gewechselt!\n"),1;
1447 return MoveMessage(sprintf("artikel %d nach muell",lasttitle[LAST_NR]+1));
1448}
1449
1450static SaveMessage(str) {
1451 mixed num;
1452 mixed *messages;
1453
1454 if (intp(str)) num=str;
1455 if ((!num && (!str || str=="" || sscanf(str,"artikel %d",num)!=1)) || num<=0) {
1456 notify_fail("Welchen Artikel willst Du abspeichern?\n");
1457 return 0;
1458 }
1459 if (!pointerp(messages=NEWSSERVER->GetNotes(GROUP)))
1460 return notify_fail("Seltsam, die Rubrik '"+GROUP+
1461 "' gibt es nicht mehr...\n"), 0;
1462 num--;
1463 if (sizeof(messages)<=num) {
1464 notify_fail("So viele Nachrichten sind da nicht !\n");
1465 return 0;
1466 }
1467 if(write_file(SAVEMSGPATH(TP),Message2string(num,messages,M2S_REMOTE)+"\n"))
1468 write(break_string(
1469 "Inhalt des Artikels wurde nach "+SAVEMSGPATH(TP)+" gespeichert.\n"));
1470 else
1471 write(break_string(
1472 "Fehler beim Schreiben nach "+SAVEMSGPATH(TP)+"!\n"));
1473 return 1;
1474}
1475
1476
1477static MailMessage(str) {
1478 mixed num,rec,group;
1479 mixed *messages;
1480
1481// printf("%O\n",inherit_list(environment(TP)));
1482// if (member(query_actions(this_player()),"mail")<0)
1483// tut nicht wegen anderer Implemtierung von AddCmd in Raeumen
1484
1485 if (str=="?"||str=="-?") return
1486 write("Syntax: versende artikel <nr> an <adresse>\n"),1;
1487
1488 str=TP->_unparsed_args(); // wegen Mailadressen
1489 if (str) str=lower_case(str);
1490
1491 if (!IS_SEER(TP) && !IS_POST(environment(TP)))
1492 return notify_fail("Du musst in ein Postamt gehen, "
1493 "um etwas versenden zu koennen.\n"),0;
1494
1495 num=0;
1496
1497 if (!str || (sscanf(str,"artikel %d an %s",num,rec)!=2 &&
1498 sscanf(str,"note %d to %s",num,rec)!=2 &&
1499 sscanf(str,"note to %s",rec)!=1 &&
1500 sscanf(str,"artikel an %s",rec)!=1)){
1501 if (!str || str[0..6]=="artikel"||str[0..3]=="note") return
1502 write("Welchen Artikel willst Du versenden, und wohin?\n"),1;
1503 else return
1504 notify_fail("Welchen Artikel willst Du versenden, und wohin?\n"),0;
1505 }
1506 if (!num&&(!pointerp(lasttitle)||sizeof(lasttitle)<LAST_SIZEOF))
1507 return write("Du hast scheinbar noch nichts gelesen, worauf man sich "
1508 "beziehen kann.\nGib notfalls die Nummer des Artikels an.\n"),1;
1509
1510 // printf("lasttitle= %O\nnum=%d\n",lasttitle,num);
1511
1512 if (!pointerp(messages=
1513 NEWSSERVER->GetNotes(group=(num?GROUP:lasttitle[LAST_GROUP]))))
1514 return notify_fail("Seltsam, die Rubrik gibt es nicht mehr...\n"), 0;
1515
1516 if (!pointerp(messages)||!sizeof(messages))
1517 return write("Die Rubrik "+group+" ist leer.\n"),1;
1518 if (num<0||sizeof(messages)<num) return
1519 write("Einen Artikel mit Nummer "+num+" gibt es in Rubrik "+group+
1520 " nicht!\n"),1;
1521
1522 if (num) num--;
1523 else {
1524 int h;
1525 num=-1;
1526 if (pointerp(messages)) {
1527 for (h=sizeof(messages)-1;
1528 (h>=0 && messages[h][M_TIME]>=lasttitle[LAST_TIME]);h--)
1529 if (messages[h][M_TIME]==lasttitle[LAST_TIME] &&
1530 lower_case(messages[h][M_WRITER])==
1531 lower_case(lasttitle[LAST_WRITER]))
1532 num=h;
1533 }
1534 if (num<0)
1535 return notify_fail("Konnte Artikel nicht wiederfinden, "
1536 "bitte gib die Nummer an.\n"),0;
1537 }
1538 MAILER->do_mail( rec,
1539 "MPA: "+messages[num][M_TITLE]+" ("+messages[num][M_WRITER]+")",
1540 Message2string(num,messages,M2S_REMOTE,group)+"\n");
1541 return 1;
1542}
1543
1544
1545
1546HelpPage(str) {
1547 if (str!="mpa"&&str!="zeitung") return 0;
1548 this_player()->More(read_file(HELPPAGE)+
1549 (IS_LEARNER(TP) ? read_file(WIZHELPPAGE) : ""));
1550 return 1;
1551}
1552
1553/*--------------------------------------------------------------------------*/
1554
1555protected void NotifyMove(object dest, object oldenv, int method) {
1556 ::NotifyMove(dest, oldenv, method);
1557
1558 // P_READ_NEWS aus dem Spieler holen.
1559 if (objectp(environment()) && query_once_interactive(environment())) {
1560 read_until=environment()->QueryProp(P_READ_NEWS);
1561 }
1562
1563 if (!mappingp(read_until) || !sizeof(read_until))
1564 InitialSubscriptions();
1565}
1566
1567int GetTID(mixed message) {
1568 string dummy;
1569 int tid;
1570 return (sscanf(message[M_MESSAGE],"%s" STATUSESCAPE " tid=%d",dummy,tid)==2)
1571 ? tid : message[M_TIME];
1572}
1573