blob: 26283a227ec1206cfdd7c238cc454f7a990c60d9 [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
Arathorneb30a702024-08-27 20:58:29 +0200297 string txt,hs,s,*m;
298 int hi,thisnr,ansiflag;
MG Mud User88f12472016-06-24 23:31:02 +0200299
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;
MG Mud User88f12472016-06-24 23:31:02 +0200349
350 if (str=="?"||str=="-?") return
351 write("Syntax: lies <nr>\n"
352 " artikel <nr>\n"
353 "Siehe auch: nn\n"),1;
354
355 if (intp(str)) num=str;
356 if ((!num && (!str || str=="" || sscanf(str,"%d",num)!=1)) || num<=0) {
357 notify_fail("WELCHE Nachricht willst Du lesen?\n");
358 return 0;
359 }
360 if (!pointerp(messages=NEWSSERVER->GetNotes(GROUP)))
361 return notify_fail("Seltsam, die Rubrik '"+GROUP+
362 "' gibt es nicht mehr...\n"), 0;
363 num--;
364 if (sizeof(messages)<=num) {
365 notify_fail("So viele Artikel sind da nicht!\n");
366 return 0;
367 }
368
369 lasttitle=({messages[num][M_TITLE],messages[num][M_WRITER],
370 messages[num][M_TIME],GetTID(messages[num]),GROUP,num});
371 this_player()->More(Message2string(messages[num],messages,M2S_VT100));
372 if (this_player() && IS_LEARNER(this_player()))
373 this_player()->save_me(1);
374 return 1;
375}
376
377static varargs mixed GetGroupName(mixed g,mixed groups) {
378 /* Name einer Rubrik. g ist int oder string, enthaelt Name oder Nummer
379 (ab 1 numeriert) */
380 mixed i,expr,gg;
381 if (!g) return write("Du solltest schon die Rubrik angeben.\n"),0;
382 if (!groups) groups=NEWSSERVER->GetGroups();
383 if (intp(i=g) || sscanf(g,"%d",i)) {
384 if (i>0 && i<=sizeof(groups)) return groups[i-1];
385 write("Eine Rubrik mit der Nummer "+i+" gibt es leider nicht.\n");
386 return 0;
387 }
388 g=lower_case(g);
389 switch(g){
390 case ".": return GROUP;
391 case "+": return groups[(member(groups,GROUP)+1)%sizeof(groups)];
392 case "-":
393 return groups[(member(groups,GROUP)-1+sizeof(groups))%sizeof(groups)];
394 }
395
396 // Existiert die Rubrik genau so?
397 if (member(groups,g)>-1) return g;
398
399 g = regreplace(g,"[[\\]\\*()?]","",1);
400 // haerteres Kriterium: Alle Abschnitte angegeben
401 expr="^"+implode(explode(g,"."),"[^\\.]*\\.")+"[^\\.]*$";
402// write("REGEXP="+expr+"\n");
403 gg=regexp(groups,expr);
404 if (sizeof(gg)==1) return gg[0];
405
406 // weicheres Kriterium: Nicht alle Abschnitte angegeben
407 expr="^(.*\\.)*"+implode(explode(g,"."),".*\\.")+".*$";
408// write("REGEXP="+expr+"\n");
409 gg=regexp(groups,expr);
410
411 if (!sizeof(gg)) {
412 write("Eine Rubrik '"+g+"' gibt es hier leider nicht.\n");
413 return 0;
414 }
415
416 if (sizeof(gg)==1) return gg[0];
417
418 write(break_string("Die Rubrik "+g+" ist nicht eindeutig. Wahrscheinlich "
419 "meinst Du eine der folgenden: "+implode(gg,", ")+".\n",78));
420 return 0;
421}
422
423static rubrik(str)
424{
MG Mud User88f12472016-06-24 23:31:02 +0200425 mixed news;
MG Mud User88f12472016-06-24 23:31:02 +0200426
427 if (str=="?"||str=="-?") return
428 write("Syntax: rubrik <rubrik>\n"
429 " wechselt die aktuelle Rubrik. Es wird die Nummer der Rubrik,\n"
430 " ihr Name oder jede eindeutige Abkuerzung akzeptiert.\n"),1;
431
432 if (!str || str==0) {
433 if (!pointerp(news=NEWSSERVER->GetNotes(GROUP))){
434 GROUP=DEFAULTGROUP;
435 if (!pointerp(news=NEWSSERVER->GetNotes(GROUP)))
436 return notify_fail("Seltsam, irgendwie geht hier einiges schief...\n"),0;
437 }
438 return write("Aktuelle Rubrik: "+GROUP+" ("+sizeof(news)+" Artikel).\n"),1;
439 }
440 str=GetGroupName(str);
441 if (!str) return 1;
442 GROUP=str;
443 news=NEWSSERVER->GetNotes(GROUP);
444 write(break_string("Ok, Du hast die Rubrik "+GROUP+" mit "+sizeof(news)+
445 " Artikel"+(sizeof(news)==1?"":"n")+" aufgeschlagen.\n",
446 78));
447 return 1;
448}
449
Arathorn2e164242020-07-27 23:49:19 +0200450int LiesArtikel(string str) {
MG Mud User88f12472016-06-24 23:31:02 +0200451 string s1;
452 int i1;
453 if ( !str ) return 0;
454 if (sscanf(str,"rubrik %s",s1))
455 return rubrik(s1);
456 if (sscanf(str,"%d",i1))
457 return lies(to_int(i1));
458 if (sscanf(str,"artikel %s",s1))
459 return lies(s1);
Arathorn2e164242020-07-27 23:49:19 +0200460 return 0;
MG Mud User88f12472016-06-24 23:31:02 +0200461}
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;
MG Mud User88f12472016-06-24 23:31:02 +0200489 int anz,i,lasttime,timeout,foundone;
490 string s;
491
492 if (arg=="?"||arg=="-?") return
493 write("Syntax: rubriken listet alle Rubriken\n"
494 " rubriken neu nur Rubriken mit ungelesenen Artikeln\n"),1;
495
496 gruppen=NEWSSERVER->GetGroups();
497 map(m_indices(read_until)-gruppen-SYSTEMGROUPS,#'KillGroup); // ');
498 s="\nEs gibt zur Zeit ";
499 anz=sizeof(gruppen);
500 if (anz==0) {
501 write(s+"keine Rubriken (wie seltsam ...)\n");
502 return 1;
503 }
504 s+=anz+" Rubrik"+(anz==1 ? "" : "en")+".";
505 if (arg=="neu") s+="\nDavon enthalten neue Artikel:\n\n";
506 else s+="\n(* oder x: enthaelt neue Artikel, x oder -: abbestellt, "
507 ">: aktuelle Rubrik)\n\n";
508 for (i=0;i<anz;i++) {
509 timeout=read_until[gruppen[i]];
510 /* GetNewsTime lieferte leider manchmal was falsches :-( */
511 /* jetzt hoffentlich richtig? Wenn nicht, das if ausklammern */
512 if ( arg!="neu" || (lasttime=NEWSSERVER->GetNewsTime(gruppen[i])) > timeout) {
513 messages=NEWSSERVER->GetNotes(gruppen[i]);
514 if (!messages || !sizeof(messages)) lasttime=0;
515 else lasttime=messages[sizeof(messages)-1][M_TIME];
516 foundone=1;
517 }
518 if (arg!="neu" || (timeout>=0 && lasttime>abs(timeout)))
519 s+=sprintf("%s%s%3d\. %-39.39s: ",
520 ((gruppen[i]==GROUP)?">":" "),
521 ((lasttime>abs(timeout)) ? ((timeout<0) ? "x" : "*")
522 : ((timeout<0) ? "-" : " ") ),
523 i+1,gruppen[i])+
524 (lasttime ? sprintf("%3d Artikel (%s)\n",
525 sizeof(messages),
526 // ((sizeof(messages)==1) ? ". " : "en."),
527 dtime(lasttime)[5..12]+ctime(lasttime)[<2..]) :
528 " - leer -\n");
529 }
530 if (arg=="neu"&&!foundone) s+="Keine Rubrik enthaelt neue Artikel.\n";
531 this_player()->More(s);
532 return 1;
533}
534
535#define M_READNEXT 1
536#define M_LISTNEW 2
537#define M_LISTNEWGR 3
538#define M_READGR 4
539
540static ReadNextUnread(str)
541{
542 string *groups,group;
543 mixed *messages;
544 int curgr,curmsg,timeout,start,nrgroups,sog,mode;
545
546 if (str=="mail") return Mail(0); /* NF Compatibility Special */
547
548 if (str=="?"||str=="-?") return
549 write("Syntax: nn naechster neuer Artikel\n"
550 " nn <rubrik> in entspr. Rubrik, wenn da was neu ist\n"
551 " nn rubriken Liste der Rubriken mit neuen Artikeln\n"
552 " nn liste Liste der ungelesenen Artikel\n"),1;
553
554 groups=NEWSSERVER->GetGroups();
555 deadTID=0;
556 map(m_indices(read_until)-groups-SYSTEMGROUPS,#'KillGroup); //'
557 nrgroups=sizeof(groups);
558 if (str && str!="rubriken" && str!="liste"){
559 if (!group=GetGroupName(str)) return 1;
560 }
561 else
562 group=0;
563 if (group && (curgr=member(groups,group)+1)) {
564 --curgr;
565 if (curgr<0 || curgr>=sizeof(groups))
566 return notify_fail("Nee... so eine Rubrik gibts hier nicht.\n"),0;
567 GROUP=group;
568 start=curgr+1;
569 mode=M_READGR;
570 write("Rubrik "+(curgr+1)+": "+GROUP+"\n");
571 } else {
572 switch (str) {
573 case 0: mode=M_READNEXT; break;
574 case "liste": mode=M_LISTNEW; write("Du hast noch nicht gelesen:\n"); break;
575 case "rubriken": return rubriken("neu");
576 default:
577 notify_fail("\
578Diesen Parameter verstehe ich nicht. Entweder gar nichts, \"liste\"\n\
579\"rubriken\", oder Name bzw. Nummer einer Rubrik.\n");
580 return 0;
581 }
582 curgr=member(groups,GROUP);
583 start=curgr+nrgroups;
584 }
585 if (!pointerp(messages=NEWSSERVER->GetNotes(GROUP))){
586 GROUP=DEFAULTGROUP;
587 if (!pointerp(messages=NEWSSERVER->GetNotes(GROUP)))
588 return notify_fail("Seltsam, irgendwie geht hier einiges schief...\n"),0;
589 }
590 timeout=read_until[GROUP];
591 curmsg=0;
592 sog=sizeof(messages);
593 while (curgr<start) {
594 ++curmsg;
595 if (curmsg>sog) {
596 if (deadTID)
597 read_until[IGNOREGROUP][GROUP]=
598 m_copy_delete(read_until[IGNOREGROUP][GROUP],deadTID);
599 ++curgr;
600 deadTID=0;
601 if (mode!=M_READGR) {
602 GROUP=groups[curgr%nrgroups];
603 timeout=read_until[GROUP];
604 if (!timeout) read_until[GROUP]=1; // Nimm neue Gruppen in Liste auf
605 if (timeout<0 || timeout>=NEWSSERVER->GetNewsTime(GROUP)) {
606 sog=0; /* Ueberlistung: Gruppe hat nix neues oder */
607 curmsg=1; /* ist unsubscribed */
608 }
609 else {
610 messages=NEWSSERVER->GetNotes(GROUP);
611 curmsg=0;
612 sog=sizeof(messages);
613 }
614 }
615 } else {
616 if ((timeout>=0 || mode==M_READGR) && messages[curmsg-1][M_TIME] > abs(timeout)) {
617 if (pointerp(this_player()->QueryProp(P_IGNORE)) &&
618 member(this_player()->QueryProp(P_IGNORE),
619 lower_case(messages[curmsg-1][M_WRITER])+".news") != -1) {
620 printf("Uebergehe ignorierten Artikel %d von %s in Rubrik %s.\n",
621 curmsg,messages[curmsg-1][M_WRITER],GROUP);
622 read_until[GROUP]=messages[curmsg-1][M_TIME];
623 if (TP) TP->SetProp(P_READ_NEWS,read_until);
624 } else if
625 (read_until[IGNOREGROUP]&&
626 read_until[IGNOREGROUP][GROUP]&&
627 CheckThreads(GROUP,messages[0][M_TIME])&& /* Tote threads weg */
628 read_until[IGNOREGROUP][GROUP][GetTID(messages[curmsg-1])]) {
629 printf("Uebergehe Artikel %d aus ignoriertem Thread.\n",curmsg);
630 read_until[IGNOREGROUP][GROUP][GetTID(messages[curmsg-1])]=
631 messages[curmsg-1][M_TIME];
632 if (deadTID&&deadTID==GetTID(messages[curmsg-1])) deadTID=0;
633 read_until[GROUP]=messages[curmsg-1][M_TIME];
634 if (TP) TP->SetProp(P_READ_NEWS,read_until);
635 } else {
636 write("\nRubrik "+(curgr%nrgroups+1)+": "+GROUP+", Artikel: "+curmsg+" von "+sog+"\n");
637 if (mode==M_LISTNEW) {
638 write(sprintf(" %-45s [%-11s] %s\n",messages[curmsg-1][M_TITLE],
639 messages[curmsg-1][M_WRITER],
640 dtime(messages[curmsg-1][M_TIME])[5..16]));
641 } else { /* mode == M_READNEXT || mode==M_READGR */
642 if (timeout>=0) read_until[GROUP]=messages[curmsg-1][M_TIME];
643 else read_until[GROUP]=-messages[curmsg-1][M_TIME];
644 if (TP) TP->SetProp(P_READ_NEWS,read_until);
645 return (lies(""+curmsg));
646 }
647 }
648 }
649 /* sonst mach einfach garnix. Schleife laeuft weiter. */
650 }
651 }
652 switch(mode) {
653 case M_LISTNEW: return 1;
654 case M_READNEXT: write((read_until[NNADWMSG]||"Nix Neues auf der Welt.")
655 +"\n"); break;
656 case M_READGR: write("Nix Neues in dieser Rubrik.\n"); break;
657 }
658 return 1;
659}
660
661
662static SetNNADWMSG(str) {
663 if (str=="?"||str=="-?") return
664 write("Syntax: zeitungsmeldung <neue Meldung> setzt Meldung\n"
665 " zeitungsmeldung loescht Meldung\n"),1;
666 if (!read_until[NNADWMSG]) {
667 write("Du hast zur Zeit keine eigene NNADW-Meldung definiert.\n");
668 if (!str) return 1;
669 }
670 else write("Deine alte NNADW-Meldung war:\n"+read_until[NNADWMSG]+"\n");
671 if (!str) {
672 read_until=m_copy_delete(read_until,NNADWMSG);
673 write("Meldung ist geloescht, es gilt wieder die Standardmeldung.\n");
674 } else {
675 read_until[NNADWMSG]=this_player()->_unparsed_args();
676 write("Deine neue Meldung lautet jetzt:\n"+read_until[NNADWMSG]+"\n");
677 }
678 if (TP) TP->SetProp(P_READ_NEWS,read_until);
679 return 1;
680}
681
682varargs int InterpretTime(mixed a,int flag) {
683 // string oder string *
684 // akzeptiert folgende Formate:
685 // dd.mm.jj (Rueckgabe: 0:00 des entsprechenden Tages)
686 // vor [<anz> d|tagen] [<anz> h|stunden] [<anz> m|minuten]
687 // flag=1: "inklusive": bei dd.mm.jj-Format 23:59:59 statt 0:00 Uhr
688
689 int i,j,k,t,nrargs;
690 string s;
691 if (stringp(a)) a=explode(a," ");
692
693// printf("%O\n",a);
694
695 if ((nrargs=sscanf(a[0],"%d.%d.%d",i,j,k))==3 ||
696 (nrargs=sscanf(a[0],"%d.%d.",i,j))==2) {
697 // Datum -> Zeit: Funktioniert im Zeitraum 1973 - ca. 2090
698 // in Zeitzonen mit ganzen Stunden ggue Rechneruhr.
699 if (nrargs==2)
700 k=70+time()/31536000;
701 if (k<70) k+=100;
702 if (k>1970) k-=1900;
703 if (k<70||k>150) return
704 write("Unzulaessiges Jahr (erlaubt: 70-heute).\n"),0;
705 t=(k-70)*31536000;
706
707 if (i<1||i>31) return write("Unzulaessiger Tag (erlaubt: 1-31).\n"),0;
708 if (j<1||j>12) return write("Unzulaessiger Monat (erlaubt: 1-12).\n"),0;
709// printf("%d.%d.%d\n",i,j,k);
710 s=ctime(t);
711 if ((j>2) && !(k%4)) t+=86400; // Schaltjahrkorrektur fuer Monate>=3
712 t+=({ 0, 2678400, 5097600, 7776000,
713 10368000, 13046400, 15638400, 18316800,
714 20995200, 23587200, 26265600, 28857600})[j-1];
715 t+=86400*(i-1);
716 t+=86400*(32-to_int(s[8..9])); // Schaltjahrkorrektur
717 t-=3600*to_int(s[11..12]); // Zeitzonenkorrektur
718 t-=3600*to_int(ctime(t)[11..12]); // Sommerzeitkorrektur
719// write("Kontrolle: "+dtime(t)+"\n");
720 if (nrargs==2 && t>time()) t-=31536000;
721 return (flag?t+86399:t);
722 }
723
724 t=0;
725 if (a[0]=="vor") for (i=sizeof(a)-1;i>0;i--) {
726 switch (a[i]) {
727 case "m":
728 case "minuten":
729 case "min":
730 case "minute":
731 t+=60*to_int(a[i-1]);
732 break;
733 case "h":
734 case "stunde":
735 case "stunden":
736 case "s":
737 t+=3600*to_int(a[i-1]);
738 break;
739 case "d":
740 case "tag":
741 case "tage":
742 case "t":
743 t+=86400*to_int(a[i-1]);
744 break;
745 default:
746 if (!to_int(a[i]))
747 write("Argumentfehler: Kann nichts mit '"+a[i]+"' anfangen.\n");
748 }
749 return time()-t;
750 }
Arathornb3051452021-05-13 21:13:03 +0200751 write("Argumentfehler.\n");
752 return 0;
MG Mud User88f12472016-06-24 23:31:02 +0200753}
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
Zesstra@Morgengrauen4090ca62016-07-19 00:22:34 +02001000mapping QueryRead() {
1001 return read_until;
MG Mud User88f12472016-06-24 23:31:02 +02001002}
1003
Zesstra@Morgengrauen4090ca62016-07-19 00:22:34 +02001004static int CatchNewsError(int err,string text4minus3) {
MG Mud User88f12472016-06-24 23:31:02 +02001005 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
Zesstra@Morgengrauen4090ca62016-07-19 00:22:34 +02001014static varargs int schreib(string str,string pretext,int called_by_itself,
1015 string statuslines)
1016{
MG Mud User88f12472016-06-24 23:31:02 +02001017 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) {
Arathorneb30a702024-08-27 20:58:29 +02001052 mixed dummy,replytitle;
MG Mud User88f12472016-06-24 23:31:02 +02001053 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) {
MG Mud User88f12472016-06-24 23:31:02 +02001145 string sig;
1146
1147 if (!text) {
1148 write("Abbruch! Artikel landet im Reisswolf.\n");
1149 return 1;
1150 }
1151 if (!sizeof(old_explode(text,"\n")-
1152 ({"q","quit"," **","** ","ende","","exit"," "})
1153 ) )
1154 return write("\
1155ACHTUNG: Wolltest Du wirklich einen Artikel ohne Inhalt in die mpa setzen?\n\
1156Artikel ohne erkennbaren Inhalt werden NICHT veroeffentlicht. Bitte ueber-\n\
1157pruef Deine Syntax, falls Du keinen Artikel schreiben wolltest, oder schreib\n\
1158auch ein bisschen Text!\n\
1159Artikel landet im Reisswolf.\n"),1;
1160 if (!message[M_MESSAGE])
1161 message[M_MESSAGE] = text;
1162 else
1163 message[M_MESSAGE]+=text;
1164 if (sig=read_file("/players/"+geteuid(this_interactive())+"/.signature"))
1165 message[M_MESSAGE]+=sig;
1166 if (!CatchNewsError(NEWSSERVER->WriteNote(message),
1167 "Diese Rubrik ist voll. Mist, da war jemand schneller...")) {
1168 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");
1169 return 0;
1170 }
1171 write("OK, Artikel ist veroeffentlicht.\n");
1172 say(capitalize(TP->name())+
1173 " hat einen Artikel in der Zeitung veroeffentlicht.\n");
1174 if (geteuid(TP)!="sitopanaki")
1175 InformPlayers(message[M_BOARD],geteuid(this_interactive()),
1176 "* MPA: Neuer Artikel von "+
1177 capitalize(geteuid(this_interactive()))+
1178 " in Rubrik \""+message[M_BOARD]+"\".\n");
1179 message=0; /* Platz sparen! */
1180 return 1;
1181}
1182
1183
1184//static // allowing aliasing *Rumata* 5/8/96
1185inhalt(str) {
1186 int i,endflag,timeout;
Arathorneb30a702024-08-27 20:58:29 +02001187 string s,txt,suche;
MG Mud User88f12472016-06-24 23:31:02 +02001188 mixed messages;
1189
1190 if (str=="?"||str=="-?") return
1191 write("Syntax: inhalt [<rubrik>] [ende] [suche <text>]\n"),1;
1192
1193 str=(!str)?({}):explode(str," ");
1194
1195 if (sizeof(str) && (str[0]=="neu" || str[0]=="neues") )
1196 return ReadNextUnread("liste"),1;
1197
1198 if (endflag=member(str,"ende")+1) str-=({"ende"});
1199 if (((i=member(str,"suche")) != -1) && (sizeof(str) > i)) {
1200 suche=lower_case(implode(str[i+1..]," "));
1201 str=str[0..i-1];
1202 }
1203 else
1204 suche=0;
1205 if (!sizeof(str)) {
1206 str=GROUP;
1207 if (!pointerp(messages=NEWSSERVER->GetNotes(str))){
1208 str=GROUP=DEFAULTGROUP;
1209 if (!pointerp(messages=NEWSSERVER->GetNotes(str)))
1210 return notify_fail("Seltsam, irgendwie geht hier einiges schief...\n"),0;
1211 }
1212 }
1213 else {
1214 str=GetGroupName(str[0]);
1215 if (!str) return 1;
1216 messages=NEWSSERVER->GetNotes(str);
1217 }
1218 timeout=abs(read_until[str]);
1219 s="Inhalt der Rubrik "+str+":\n\n";
1220 if (!pointerp(messages) || !sizeof(messages))
1221 return
1222 write(s+"Zur Zeit befinden sich keine Artikel in dieser Rubrik.\n"),1;
1223 if (suche)
1224 s+="Suche nach '"+suche+"' in der Rubrik ergab folgende Treffer:\n\n";
1225 else
1226 if (sizeof(messages)==1)
1227 s+="Zur Zeit befindet sich ein Artikel in der Rubrik:\n\n";
1228 else
1229 s+="Zur Zeit befinden sich "+sizeof(messages)+
1230 " Artikel in der Rubrik:\n\n";
1231 if (endflag&&(sizeof(messages)>16)&&
1232 messages[sizeof(messages)-16][M_TIME]>=timeout) timeout=-1;
1233 for (i=(endflag?(((endflag=sizeof(messages)-15)<0)?0:endflag):0);
1234 i<sizeof(messages);i++)
1235 {
1236 txt=sprintf("%2d.%s%-48s%4d (%-11s) %s\n",i+1,
1237 (((timeout>=0) && timeout<messages[i][M_TIME] )?
1238 ( (timeout=-1),"*"):" "),messages[i][M_TITLE],
1239 sizeof(explode(messages[i][M_MESSAGE],"\n")),
1240 messages[i][M_WRITER],
1241 dtime(messages[i][M_TIME])[5..11]);
1242 if (!suche || (strstr(lower_case(txt), suche) != -1))
1243 s+=txt;
1244 }
1245 if (endflag) write(s);
1246 else this_player()->More(s);
1247 return 1;
1248}
1249
1250
1251static artikel(str) {
1252 return lies(str);
1253}
1254
1255
Zesstra@Morgengrauen795a0e12016-07-19 00:17:42 +02001256static int loesche(string str) {
MG Mud User88f12472016-06-24 23:31:02 +02001257 int num;
1258 mixed *messages;
1259
1260 if (str=="?"||str=="-?") return
1261 write("Syntax: loesche artikel <nr>\n"
1262 " (bezieht sich immer auf die aktuelle Rubrik.\n"),1;
1263
1264 if (!str || sscanf(str,"artikel %d",num)!=1 || num<=0)
1265 return notify_fail("WELCHEN Artikel willst Du loeschen ?\n"),0;
1266 num--;
1267 messages=(NEWSSERVER->GetNotes(GROUP));
1268 if (sizeof(messages)<=num) return
1269 notify_fail("So viele Artikel sind da nicht!\n"),0;
1270
1271 write("Rubrik "+GROUP+", Artikel "+(num+1)+
1272 " von "+capitalize(messages[num][M_WRITER])+
1273 " vom "+dtime(messages[num][M_TIME])[5..26]+
1274 ",\nTitel: "+messages[num][M_TITLE]+",\n\n");
1275
1276 /* (ueberfluessige Abfrage, macht schon /secure/news)
1277 if (!IS_LEARNER(TI) && lower_case(messages[num][M_WRITER])!=geteuid(TI))
1278 return
1279 write("Nicht geloescht - du darfst nur eigene Artikel loeschen.\n"),1;
1280 */
1281
1282 switch (NEWSSERVER->RemoveNote(GROUP, num)){
1283 case 1: write("Artikel ist geloescht.\n");
1284 say(this_player()->name()+" loescht einen Artikel aus der Zeitung.\n");
1285 return 1;
1286 case -1: write("Diesen Artikel darfst Du nicht loeschen.\n");
1287 say(this_player()->name()+" versucht vergeblich, einen Artikel zu loeschen.\n");
1288 return 1;
1289 case -3: write("So viele Artikel sind da nicht !\n");
1290 return 1;
1291 default: write("Interner Fehler. Bitte Erzmagier verstaendigen !\n");
1292 return 1;
Zesstra@Morgengrauen4090ca62016-07-19 00:22:34 +02001293 }
MG Mud User88f12472016-06-24 23:31:02 +02001294}
1295
1296// Low-level Funktion zum Abonnieren/Abbestellen von Rubriken
1297// bestellen==0 -> abbestellen, bestellen!=0 -> bestellen
1298// Rueckgabe: 0, wenn der gewuenschte Zustand schon eingestellt war, sonst 1
1299private int _subscribe(string groupname, int bestellen) {
1300
1301 int timeout = read_until[groupname];
1302 // gar nicht abonniert/abbestellt?
1303 if (!bestellen && timeout < 0)
1304 return 0;
1305 else if (bestellen && timeout > 0)
1306 return 0;
1307
1308 // wenn noch kein timeout, erstmal auf 1 setzen
1309 timeout ||= 1;
1310
1311 // -1 fuer abbestellen, +1 fuer bestellen
1312 if (bestellen)
1313 read_until[groupname] = abs(timeout);
1314 else
1315 read_until[groupname] = -timeout;
1316
1317 if (environment())
1318 environment()->SetProp(P_READ_NEWS, read_until);
1319
1320 return 1;
1321}
1322
1323static Unsubscribe(str) {
MG Mud User88f12472016-06-24 23:31:02 +02001324 if (str=="?"||str=="-?") return
1325 write("Syntax: unsubscribe <rubrik>"
1326 " oder: bestelle <rubrik> ab\n"),1;
1327 str=GetGroupName(str);
1328 if (!str) return 1;
1329 if (!_subscribe(str,0)) {
1330 notify_fail("Die Rubrik hast Du gar nicht abonniert!\n");
1331 return 0;
1332 }
1333 else {
1334 write("Rubrik "+str+" abbestellt.\n");
1335 }
1336 return 1;
1337}
1338
1339
1340static Bestelle(str) { /* ab ! */
1341 if (!str || !sscanf(str,"%s ab",str)) return _notify_fail(
1342 "Die Syntax ist: 'bestelle <rubrik> ab', "
1343 "oder meinst Du 'abonniere'?\n"),0;
1344 return Unsubscribe(str);
1345}
1346
1347static Subscribe(str) {
MG Mud User88f12472016-06-24 23:31:02 +02001348 if (str=="?"||str=="-?") return
1349 write("Syntax: abonniere <rubrik>\n"
1350 " oder: subscribe <rubrik>\n"),1;
1351 str=GetGroupName(str);
1352 if (!str) return 1;
1353 if (!_subscribe(str,1)) {
1354 notify_fail("Die Rubrik hast Du doch schon abonniert!\n");
1355 return 0;
1356 }
1357 else {
1358 write("Rubrik "+str+" abonniert.\n");
1359 }
1360 return 1;
1361}
1362
1363// Legt die anfaenglichen Abonnements eines Neulesers fest und bestellt alle
1364// anderen ab.
1365private void InitialSubscriptions() {
1366 // alle abbestellen. ;-)
1367 // Alternative: fuer alle _subscribe(,0) rufen
1368 if (!query_once_interactive(environment()))
1369 return;
1370 string *gruppen = NEWSSERVER->GetGroups();
1371 int *vals = allocate(sizeof(gruppen),-1);
1372 read_until = mkmapping(gruppen,vals);
1373
1374 // jetzt die vorausgewaehlten bestellen
1375 foreach(string gruppe : INITIAL_SUBSCRIPTIONS) {
1376 if (member(gruppen, gruppe) > -1)
1377 _subscribe(gruppe,1);
1378 }
1379 // und ggf. noch die eigene Gildenrubrik
1380 string gilde = environment()->QueryProp(P_GUILD);
1381 if (stringp(gilde)
1382 && member(gruppen, "gilden."+gilde) > -1)
1383 _subscribe("gilden."+gilde,1);
1384
1385 environment()->SetProp(P_READ_NEWS, read_until);
1386}
1387
1388static MoveMessage(str) {
Arathorneb30a702024-08-27 20:58:29 +02001389 int num;
MG Mud User88f12472016-06-24 23:31:02 +02001390 mixed msg/*,expl*/;
1391 string gr;
1392 if (str=="?"||str=="-?") return
1393 write("Syntax: verlege artikel <nr> nach <rubrik>\n"
1394 " Artikel und Rubrik muessen explizit angegeben werden.\n"),1;
1395 if (!str || sscanf(str,"artikel %d nach %s",num,gr)!=2) return (int)notify_fail(
1396 "verlege artikel <nr> nach <rubrik>, oder was?\n");
1397 if (!(gr=GetGroupName(gr))) return 1;
Zesstra@Morgengrauen0e0ac492016-07-19 00:13:51 +02001398 if (gr == GROUP)
1399 {
1400 write("Das waere reichlich sinnlos, nicht wahr?\n");
1401 return 1;
1402 }
MG Mud User88f12472016-06-24 23:31:02 +02001403 if (!(CatchNewsError(NEWSSERVER->AskAllowedWrite(gr),"Die Rubrik ist leider voll.\n"))) return 1;
1404
1405 if (!pointerp(msg=NEWSSERVER->GetNotes(GROUP)))
1406 return notify_fail("Seltsam, die Rubrik '"+GROUP+
1407 "' gibt es nicht mehr...\n"), 0;
1408
1409 num--;
1410 if (sizeof(msg)<=num) return
1411 notify_fail("So viele Nachrichten sind da nicht !\n"),0;
1412 msg=msg[num];
1413 if (geteuid(TI) != lower_case(msg[M_WRITER])) {
1414 if (!IS_LEARNER(TI)) return
1415 write("Du darfst nur Deine eigenen Artikel verlegen.\n"),1;
1416 write("WARNUNG: Das ist nicht Dein eigener Artikel!\n");
1417 }
1418 // return (int)notify_fail("Man darf zur Zeit nur eigene Artikel verlegen.\n");
1419 if (!CatchNewsError(NEWSSERVER->RemoveNote(GROUP,num),"Dieser Fehler kann eigentlich nicht auftreten"))
1420 write("Warnung! Konnte Artikel an alter Position nicht loeschen.\n");
1421 else write("Artikel von Rubrik "+GROUP+" entfernt.\n");
1422
1423 msg[M_MESSAGE]=
1424 sprintf("%s on=%s ot=%d og=%s\n",
1425 STATUSESCAPE,msg[M_WRITER],msg[M_TIME],msg[M_BOARD])
1426 +msg[M_MESSAGE];
1427
1428/*
1429 expl=explode(msg[M_MESSAGE],"\n");
1430 for (i=0;(IS_STATUSLINE(expl[i][0..2]));i++);
1431 msg[M_MESSAGE]=( (i) ? implode(expl[0..i-1],"\n")+"\n" : "" ) +
1432 "[Verlegt von "+msg[M_BOARD]+", "+msg[M_WRITER]+", "+
1433 dtime(msg[M_TIME])[5..26]+"]:\n"+
1434 implode(expl[i..],"\n")+"\n";
1435*/
1436
1437 msg[M_BOARD]=gr;
1438 NEWSSERVER->WriteNote(msg);
1439 write("Artikel nach Rubrik "+gr+" verlegt.\n");
1440 return 1;
1441}
1442
1443static MoveTrash()
1444{
1445 if (!pointerp(lasttitle)||sizeof(lasttitle)<LAST_SIZEOF) return
1446 write("Was denn bitte? Du hast noch gar nichts gelesen!\n"),1;
1447 if (lasttitle[LAST_GROUP]!=GROUP) return
1448 write("Nix gibts! Du hast die Rubrik gewechselt!\n"),1;
1449 return MoveMessage(sprintf("artikel %d nach muell",lasttitle[LAST_NR]+1));
1450}
1451
1452static SaveMessage(str) {
1453 mixed num;
1454 mixed *messages;
1455
1456 if (intp(str)) num=str;
1457 if ((!num && (!str || str=="" || sscanf(str,"artikel %d",num)!=1)) || num<=0) {
1458 notify_fail("Welchen Artikel willst Du abspeichern?\n");
1459 return 0;
1460 }
1461 if (!pointerp(messages=NEWSSERVER->GetNotes(GROUP)))
1462 return notify_fail("Seltsam, die Rubrik '"+GROUP+
1463 "' gibt es nicht mehr...\n"), 0;
1464 num--;
1465 if (sizeof(messages)<=num) {
1466 notify_fail("So viele Nachrichten sind da nicht !\n");
1467 return 0;
1468 }
1469 if(write_file(SAVEMSGPATH(TP),Message2string(num,messages,M2S_REMOTE)+"\n"))
1470 write(break_string(
1471 "Inhalt des Artikels wurde nach "+SAVEMSGPATH(TP)+" gespeichert.\n"));
1472 else
1473 write(break_string(
1474 "Fehler beim Schreiben nach "+SAVEMSGPATH(TP)+"!\n"));
1475 return 1;
1476}
1477
1478
1479static MailMessage(str) {
1480 mixed num,rec,group;
1481 mixed *messages;
1482
1483// printf("%O\n",inherit_list(environment(TP)));
1484// if (member(query_actions(this_player()),"mail")<0)
1485// tut nicht wegen anderer Implemtierung von AddCmd in Raeumen
1486
1487 if (str=="?"||str=="-?") return
1488 write("Syntax: versende artikel <nr> an <adresse>\n"),1;
1489
1490 str=TP->_unparsed_args(); // wegen Mailadressen
1491 if (str) str=lower_case(str);
1492
1493 if (!IS_SEER(TP) && !IS_POST(environment(TP)))
1494 return notify_fail("Du musst in ein Postamt gehen, "
1495 "um etwas versenden zu koennen.\n"),0;
1496
1497 num=0;
1498
1499 if (!str || (sscanf(str,"artikel %d an %s",num,rec)!=2 &&
1500 sscanf(str,"note %d to %s",num,rec)!=2 &&
1501 sscanf(str,"note to %s",rec)!=1 &&
1502 sscanf(str,"artikel an %s",rec)!=1)){
1503 if (!str || str[0..6]=="artikel"||str[0..3]=="note") return
1504 write("Welchen Artikel willst Du versenden, und wohin?\n"),1;
1505 else return
1506 notify_fail("Welchen Artikel willst Du versenden, und wohin?\n"),0;
1507 }
1508 if (!num&&(!pointerp(lasttitle)||sizeof(lasttitle)<LAST_SIZEOF))
1509 return write("Du hast scheinbar noch nichts gelesen, worauf man sich "
1510 "beziehen kann.\nGib notfalls die Nummer des Artikels an.\n"),1;
1511
1512 // printf("lasttitle= %O\nnum=%d\n",lasttitle,num);
1513
1514 if (!pointerp(messages=
1515 NEWSSERVER->GetNotes(group=(num?GROUP:lasttitle[LAST_GROUP]))))
1516 return notify_fail("Seltsam, die Rubrik gibt es nicht mehr...\n"), 0;
1517
1518 if (!pointerp(messages)||!sizeof(messages))
1519 return write("Die Rubrik "+group+" ist leer.\n"),1;
1520 if (num<0||sizeof(messages)<num) return
1521 write("Einen Artikel mit Nummer "+num+" gibt es in Rubrik "+group+
1522 " nicht!\n"),1;
1523
1524 if (num) num--;
1525 else {
1526 int h;
1527 num=-1;
1528 if (pointerp(messages)) {
1529 for (h=sizeof(messages)-1;
1530 (h>=0 && messages[h][M_TIME]>=lasttitle[LAST_TIME]);h--)
1531 if (messages[h][M_TIME]==lasttitle[LAST_TIME] &&
1532 lower_case(messages[h][M_WRITER])==
1533 lower_case(lasttitle[LAST_WRITER]))
1534 num=h;
1535 }
1536 if (num<0)
1537 return notify_fail("Konnte Artikel nicht wiederfinden, "
1538 "bitte gib die Nummer an.\n"),0;
1539 }
1540 MAILER->do_mail( rec,
1541 "MPA: "+messages[num][M_TITLE]+" ("+messages[num][M_WRITER]+")",
1542 Message2string(num,messages,M2S_REMOTE,group)+"\n");
1543 return 1;
1544}
1545
1546
1547
1548HelpPage(str) {
1549 if (str!="mpa"&&str!="zeitung") return 0;
1550 this_player()->More(read_file(HELPPAGE)+
1551 (IS_LEARNER(TP) ? read_file(WIZHELPPAGE) : ""));
1552 return 1;
1553}
1554
1555/*--------------------------------------------------------------------------*/
1556
1557protected void NotifyMove(object dest, object oldenv, int method) {
1558 ::NotifyMove(dest, oldenv, method);
1559
1560 // P_READ_NEWS aus dem Spieler holen.
1561 if (objectp(environment()) && query_once_interactive(environment())) {
1562 read_until=environment()->QueryProp(P_READ_NEWS);
1563 }
1564
1565 if (!mappingp(read_until) || !sizeof(read_until))
1566 InitialSubscriptions();
1567}
1568
1569int GetTID(mixed message) {
MG Mud User88f12472016-06-24 23:31:02 +02001570 int tid;
Arathorneb30a702024-08-27 20:58:29 +02001571 return (sscanf(message[M_MESSAGE],"%~s" STATUSESCAPE " tid=%d",tid)==2)
MG Mud User88f12472016-06-24 23:31:02 +02001572 ? tid : message[M_TIME];
1573}
1574