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