blob: 3c2dd4f3e33f875aeef82e91e8ba4f1a01c86fd7 [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
Arathorn2e164242020-07-27 23:49:19 +0200453int LiesArtikel(string str) {
MG Mud User88f12472016-06-24 23:31:02 +0200454 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);
Arathorn2e164242020-07-27 23:49:19 +0200463 return 0;
MG Mud User88f12472016-06-24 23:31:02 +0200464}
465
466
467/* Ueberpruefe, ob in Rubrik tote threads ignoriert werden. Tot bedeutet,
468 dass der letzte darin uebergangene Artikel bereits expired ist UND
469 keine Artikel aus diesem thread mehr vorhanden sind.
470 ACHTUNG: Es kann passieren, dass dazwischen noch ein neuer Artikel
471 dazugekommen ist.
472 Hier wird auf expired geprueft und ggf Variable deadTID gesetzt. Wird beim
473 Lesen mit nn ein Artikel mit dieser TID gefunden (passiert direkt hinter
474 Pruefung), wird deadTID wieder auf 0 gesetzt. Ist deadTID beim Umschalten
475 auf naechste Rubrik !=0, ist der thread tot.
476*/
477
478static int CheckThreads(string rubrik,int timeout) {
479 mixed tids;
480 int i;
481
482// deadTID=0;
483 tids=m_indices(read_until[IGNOREGROUP][rubrik]);
484 for (i=sizeof(tids)-1;i>=0&&!deadTID;i--)
485 if (read_until[IGNOREGROUP][rubrik][tids[i]]<timeout) deadTID=tids[i];
486 return 1;
487}
488
489static int rubriken(mixed arg)
490{
491 mixed *gruppen, *messages;
492 mixed news;
493 int anz,i,lasttime,timeout,foundone;
494 string s;
495
496 if (arg=="?"||arg=="-?") return
497 write("Syntax: rubriken listet alle Rubriken\n"
498 " rubriken neu nur Rubriken mit ungelesenen Artikeln\n"),1;
499
500 gruppen=NEWSSERVER->GetGroups();
501 map(m_indices(read_until)-gruppen-SYSTEMGROUPS,#'KillGroup); // ');
502 s="\nEs gibt zur Zeit ";
503 anz=sizeof(gruppen);
504 if (anz==0) {
505 write(s+"keine Rubriken (wie seltsam ...)\n");
506 return 1;
507 }
508 s+=anz+" Rubrik"+(anz==1 ? "" : "en")+".";
509 if (arg=="neu") s+="\nDavon enthalten neue Artikel:\n\n";
510 else s+="\n(* oder x: enthaelt neue Artikel, x oder -: abbestellt, "
511 ">: aktuelle Rubrik)\n\n";
512 for (i=0;i<anz;i++) {
513 timeout=read_until[gruppen[i]];
514 /* GetNewsTime lieferte leider manchmal was falsches :-( */
515 /* jetzt hoffentlich richtig? Wenn nicht, das if ausklammern */
516 if ( arg!="neu" || (lasttime=NEWSSERVER->GetNewsTime(gruppen[i])) > timeout) {
517 messages=NEWSSERVER->GetNotes(gruppen[i]);
518 if (!messages || !sizeof(messages)) lasttime=0;
519 else lasttime=messages[sizeof(messages)-1][M_TIME];
520 foundone=1;
521 }
522 if (arg!="neu" || (timeout>=0 && lasttime>abs(timeout)))
523 s+=sprintf("%s%s%3d\. %-39.39s: ",
524 ((gruppen[i]==GROUP)?">":" "),
525 ((lasttime>abs(timeout)) ? ((timeout<0) ? "x" : "*")
526 : ((timeout<0) ? "-" : " ") ),
527 i+1,gruppen[i])+
528 (lasttime ? sprintf("%3d Artikel (%s)\n",
529 sizeof(messages),
530 // ((sizeof(messages)==1) ? ". " : "en."),
531 dtime(lasttime)[5..12]+ctime(lasttime)[<2..]) :
532 " - leer -\n");
533 }
534 if (arg=="neu"&&!foundone) s+="Keine Rubrik enthaelt neue Artikel.\n";
535 this_player()->More(s);
536 return 1;
537}
538
539#define M_READNEXT 1
540#define M_LISTNEW 2
541#define M_LISTNEWGR 3
542#define M_READGR 4
543
544static ReadNextUnread(str)
545{
546 string *groups,group;
547 mixed *messages;
548 int curgr,curmsg,timeout,start,nrgroups,sog,mode;
549
550 if (str=="mail") return Mail(0); /* NF Compatibility Special */
551
552 if (str=="?"||str=="-?") return
553 write("Syntax: nn naechster neuer Artikel\n"
554 " nn <rubrik> in entspr. Rubrik, wenn da was neu ist\n"
555 " nn rubriken Liste der Rubriken mit neuen Artikeln\n"
556 " nn liste Liste der ungelesenen Artikel\n"),1;
557
558 groups=NEWSSERVER->GetGroups();
559 deadTID=0;
560 map(m_indices(read_until)-groups-SYSTEMGROUPS,#'KillGroup); //'
561 nrgroups=sizeof(groups);
562 if (str && str!="rubriken" && str!="liste"){
563 if (!group=GetGroupName(str)) return 1;
564 }
565 else
566 group=0;
567 if (group && (curgr=member(groups,group)+1)) {
568 --curgr;
569 if (curgr<0 || curgr>=sizeof(groups))
570 return notify_fail("Nee... so eine Rubrik gibts hier nicht.\n"),0;
571 GROUP=group;
572 start=curgr+1;
573 mode=M_READGR;
574 write("Rubrik "+(curgr+1)+": "+GROUP+"\n");
575 } else {
576 switch (str) {
577 case 0: mode=M_READNEXT; break;
578 case "liste": mode=M_LISTNEW; write("Du hast noch nicht gelesen:\n"); break;
579 case "rubriken": return rubriken("neu");
580 default:
581 notify_fail("\
582Diesen Parameter verstehe ich nicht. Entweder gar nichts, \"liste\"\n\
583\"rubriken\", oder Name bzw. Nummer einer Rubrik.\n");
584 return 0;
585 }
586 curgr=member(groups,GROUP);
587 start=curgr+nrgroups;
588 }
589 if (!pointerp(messages=NEWSSERVER->GetNotes(GROUP))){
590 GROUP=DEFAULTGROUP;
591 if (!pointerp(messages=NEWSSERVER->GetNotes(GROUP)))
592 return notify_fail("Seltsam, irgendwie geht hier einiges schief...\n"),0;
593 }
594 timeout=read_until[GROUP];
595 curmsg=0;
596 sog=sizeof(messages);
597 while (curgr<start) {
598 ++curmsg;
599 if (curmsg>sog) {
600 if (deadTID)
601 read_until[IGNOREGROUP][GROUP]=
602 m_copy_delete(read_until[IGNOREGROUP][GROUP],deadTID);
603 ++curgr;
604 deadTID=0;
605 if (mode!=M_READGR) {
606 GROUP=groups[curgr%nrgroups];
607 timeout=read_until[GROUP];
608 if (!timeout) read_until[GROUP]=1; // Nimm neue Gruppen in Liste auf
609 if (timeout<0 || timeout>=NEWSSERVER->GetNewsTime(GROUP)) {
610 sog=0; /* Ueberlistung: Gruppe hat nix neues oder */
611 curmsg=1; /* ist unsubscribed */
612 }
613 else {
614 messages=NEWSSERVER->GetNotes(GROUP);
615 curmsg=0;
616 sog=sizeof(messages);
617 }
618 }
619 } else {
620 if ((timeout>=0 || mode==M_READGR) && messages[curmsg-1][M_TIME] > abs(timeout)) {
621 if (pointerp(this_player()->QueryProp(P_IGNORE)) &&
622 member(this_player()->QueryProp(P_IGNORE),
623 lower_case(messages[curmsg-1][M_WRITER])+".news") != -1) {
624 printf("Uebergehe ignorierten Artikel %d von %s in Rubrik %s.\n",
625 curmsg,messages[curmsg-1][M_WRITER],GROUP);
626 read_until[GROUP]=messages[curmsg-1][M_TIME];
627 if (TP) TP->SetProp(P_READ_NEWS,read_until);
628 } else if
629 (read_until[IGNOREGROUP]&&
630 read_until[IGNOREGROUP][GROUP]&&
631 CheckThreads(GROUP,messages[0][M_TIME])&& /* Tote threads weg */
632 read_until[IGNOREGROUP][GROUP][GetTID(messages[curmsg-1])]) {
633 printf("Uebergehe Artikel %d aus ignoriertem Thread.\n",curmsg);
634 read_until[IGNOREGROUP][GROUP][GetTID(messages[curmsg-1])]=
635 messages[curmsg-1][M_TIME];
636 if (deadTID&&deadTID==GetTID(messages[curmsg-1])) deadTID=0;
637 read_until[GROUP]=messages[curmsg-1][M_TIME];
638 if (TP) TP->SetProp(P_READ_NEWS,read_until);
639 } else {
640 write("\nRubrik "+(curgr%nrgroups+1)+": "+GROUP+", Artikel: "+curmsg+" von "+sog+"\n");
641 if (mode==M_LISTNEW) {
642 write(sprintf(" %-45s [%-11s] %s\n",messages[curmsg-1][M_TITLE],
643 messages[curmsg-1][M_WRITER],
644 dtime(messages[curmsg-1][M_TIME])[5..16]));
645 } else { /* mode == M_READNEXT || mode==M_READGR */
646 if (timeout>=0) read_until[GROUP]=messages[curmsg-1][M_TIME];
647 else read_until[GROUP]=-messages[curmsg-1][M_TIME];
648 if (TP) TP->SetProp(P_READ_NEWS,read_until);
649 return (lies(""+curmsg));
650 }
651 }
652 }
653 /* sonst mach einfach garnix. Schleife laeuft weiter. */
654 }
655 }
656 switch(mode) {
657 case M_LISTNEW: return 1;
658 case M_READNEXT: write((read_until[NNADWMSG]||"Nix Neues auf der Welt.")
659 +"\n"); break;
660 case M_READGR: write("Nix Neues in dieser Rubrik.\n"); break;
661 }
662 return 1;
663}
664
665
666static SetNNADWMSG(str) {
667 if (str=="?"||str=="-?") return
668 write("Syntax: zeitungsmeldung <neue Meldung> setzt Meldung\n"
669 " zeitungsmeldung loescht Meldung\n"),1;
670 if (!read_until[NNADWMSG]) {
671 write("Du hast zur Zeit keine eigene NNADW-Meldung definiert.\n");
672 if (!str) return 1;
673 }
674 else write("Deine alte NNADW-Meldung war:\n"+read_until[NNADWMSG]+"\n");
675 if (!str) {
676 read_until=m_copy_delete(read_until,NNADWMSG);
677 write("Meldung ist geloescht, es gilt wieder die Standardmeldung.\n");
678 } else {
679 read_until[NNADWMSG]=this_player()->_unparsed_args();
680 write("Deine neue Meldung lautet jetzt:\n"+read_until[NNADWMSG]+"\n");
681 }
682 if (TP) TP->SetProp(P_READ_NEWS,read_until);
683 return 1;
684}
685
686varargs int InterpretTime(mixed a,int flag) {
687 // string oder string *
688 // akzeptiert folgende Formate:
689 // dd.mm.jj (Rueckgabe: 0:00 des entsprechenden Tages)
690 // vor [<anz> d|tagen] [<anz> h|stunden] [<anz> m|minuten]
691 // flag=1: "inklusive": bei dd.mm.jj-Format 23:59:59 statt 0:00 Uhr
692
693 int i,j,k,t,nrargs;
694 string s;
695 if (stringp(a)) a=explode(a," ");
696
697// printf("%O\n",a);
698
699 if ((nrargs=sscanf(a[0],"%d.%d.%d",i,j,k))==3 ||
700 (nrargs=sscanf(a[0],"%d.%d.",i,j))==2) {
701 // Datum -> Zeit: Funktioniert im Zeitraum 1973 - ca. 2090
702 // in Zeitzonen mit ganzen Stunden ggue Rechneruhr.
703 if (nrargs==2)
704 k=70+time()/31536000;
705 if (k<70) k+=100;
706 if (k>1970) k-=1900;
707 if (k<70||k>150) return
708 write("Unzulaessiges Jahr (erlaubt: 70-heute).\n"),0;
709 t=(k-70)*31536000;
710
711 if (i<1||i>31) return write("Unzulaessiger Tag (erlaubt: 1-31).\n"),0;
712 if (j<1||j>12) return write("Unzulaessiger Monat (erlaubt: 1-12).\n"),0;
713// printf("%d.%d.%d\n",i,j,k);
714 s=ctime(t);
715 if ((j>2) && !(k%4)) t+=86400; // Schaltjahrkorrektur fuer Monate>=3
716 t+=({ 0, 2678400, 5097600, 7776000,
717 10368000, 13046400, 15638400, 18316800,
718 20995200, 23587200, 26265600, 28857600})[j-1];
719 t+=86400*(i-1);
720 t+=86400*(32-to_int(s[8..9])); // Schaltjahrkorrektur
721 t-=3600*to_int(s[11..12]); // Zeitzonenkorrektur
722 t-=3600*to_int(ctime(t)[11..12]); // Sommerzeitkorrektur
723// write("Kontrolle: "+dtime(t)+"\n");
724 if (nrargs==2 && t>time()) t-=31536000;
725 return (flag?t+86399:t);
726 }
727
728 t=0;
729 if (a[0]=="vor") for (i=sizeof(a)-1;i>0;i--) {
730 switch (a[i]) {
731 case "m":
732 case "minuten":
733 case "min":
734 case "minute":
735 t+=60*to_int(a[i-1]);
736 break;
737 case "h":
738 case "stunde":
739 case "stunden":
740 case "s":
741 t+=3600*to_int(a[i-1]);
742 break;
743 case "d":
744 case "tag":
745 case "tage":
746 case "t":
747 t+=86400*to_int(a[i-1]);
748 break;
749 default:
750 if (!to_int(a[i]))
751 write("Argumentfehler: Kann nichts mit '"+a[i]+"' anfangen.\n");
752 }
753 return time()-t;
754 }
Arathornb3051452021-05-13 21:13:03 +0200755 write("Argumentfehler.\n");
756 return 0;
MG Mud User88f12472016-06-24 23:31:02 +0200757}
758
759static Catchup(string str)
760{
761 int welche,zeit,i;
762 string gr;
763 mixed groups,news,args;
764
765 if (!pointerp(NEWSSERVER->GetNotes(GROUP)))
766 return notify_fail("Seltsam, die Rubrik '"+GROUP+
767 "' gibt es nicht mehr...\n"), 0;
768
769 str=this_player()->_unparsed_args(); // wg. Datum
770 if (str) str=lower_case(str);
771 else str=GROUP; // default: aktuelle Rubrik komplett.
772
773 if (str=="?"|| str=="-?") return CatchupSyntax();
774
775 // uebergehe Antworten (Thread ignorieren)
776 if (str&&(str[0..6]=="antwort"||str=="thread")) {
777 if (!pointerp(lasttitle)) return
778 write("Du hast bisher noch keinen Artikel gelesen, damit kann ich nicht wissen,\nwelchen Thread du uebergehen willst.\n"),1;
779 if (!read_until[IGNOREGROUP]) read_until[IGNOREGROUP]=([]);
780 if (!read_until[IGNOREGROUP][GROUP]) read_until[IGNOREGROUP][GROUP]=([]);
781 if (read_until[IGNOREGROUP][GROUP][lasttitle[3]]) {
782 read_until[IGNOREGROUP][GROUP]=m_copy_delete(read_until[IGNOREGROUP][GROUP],lasttitle[3]);
783 write("Dieser Thread wird jetzt nicht mehr uebergangen.\n");
784 } else {
785 read_until[IGNOREGROUP][GROUP][lasttitle[3]]=lasttitle[2];
786 write("Dieser Thread wird ab sofort uebergangen.\nFalls das ein Irrtum war, wiederhole den Befehl augenblicklich.\n");
787 }
788 if (TP) TP->SetProp(P_READ_NEWS,read_until);
789 return 1;
790 }
791
792 groups=NEWSSERVER->GetGroups();
793
794 args=explode(str," ");
795
796 // Uebergehe alles
797
798 if (args[0]=="alle" || args[0]=="alles" || args[0]=="all") {
799 if (sizeof(args)<=1) zeit=time()-1;
800 else if (args[1]!="bis") return CatchupSyntax();
801 else if (sizeof(args)<3) return CatchupSyntax();
802
803 else zeit=InterpretTime(args[2..],1);
804 if (zeit>time()) zeit=time()-1;
805 write("Uebergehe alle Rubriken bis "+dtime(zeit)+".\n");
806 for (welche=0;welche<sizeof(groups);++welche) {
807 gr=groups[welche];
808// zeit=NEWSSERVER->GetNewsTime(gr);
809 if (abs(read_until[gr])<zeit)
810 read_until[gr]=(read_until[gr]>=0)?zeit:-zeit;
811 if (TP) TP->SetProp(P_READ_NEWS,read_until);
812 }
813 return 1;
814 }
815
816 // Anzahl Artikel
817
818 if (sizeof(args)>=2 && args[1]=="artikel") {
819 if (!to_int(args[0])) return CatchupSyntax();
820 news=NEWSSERVER->GetNotes(GROUP);
821 for (i=sizeof(news)-1;i>=0&&news[i][M_TIME]>read_until[GROUP];i--);
822 welche=i+to_int(args[0]);
823 if (welche>=sizeof(news)) welche=sizeof(news)-1;
824 write("Uebergehe die naechsten "+(welche-i)+" Artikel in Rubrik "+
825 GROUP+"\n.");
826 if (welche>=0) {
827 zeit=news[welche][M_TIME];
828 read_until[GROUP]=(read_until[GROUP]>=0)?zeit:-zeit;
829 if (TP) TP->SetProp(P_READ_NEWS,read_until);
830 }
831 return 1;
832 }
833
834 // einzelne Rubrik.
835
836 if (!(gr=GetGroupName(args[0]))) return 1;
837 news=NEWSSERVER->GetNotes(gr);
838 if (!sizeof(news)) {
839 write("Rubrik "+gr+" ist leer.\n");
840 return 1;
841 }
842// zeit=news[sizeof(news)-1][M_TIME];
843 if (sizeof(args)<=1)
844 zeit=time();
845 else
846 if (args[1]!="bis") return CatchupSyntax();
847 else
848 zeit=InterpretTime(args[2..],1);
849 if (zeit>time()) zeit=time();
850 read_until[gr]=zeit;
851 if (TP) TP->SetProp(P_READ_NEWS,read_until);
852 write("Uebergehe "+gr+" bis "+dtime(zeit)+",\nletzter Artikel war vom "+
853 dtime(NEWSSERVER->GetNewsTime(gr))+"\n");
854 return 1;
855}
856
857
858static Ignore(str) {
859 if (str=="thread"||str=="antworten") return Catchup(str);
860 return 0;
861}
862
863static CatchupSyntax() {
864 write("Syntax des Befehls uebergehe (oder catchup):\n"
865 " uebergehe [rubrik] (default: aktuelle Rubrik)\n"
866 " uebergehe alles (in allen Rubriken)\n"
867 " uebergehe <anz> artikel (in akt. Rubrik)\n"
868 " uebergehe [rubrik]|alles bis <tag>.<monat>.[<jahr>]\n"
869 " uebergehe [rubrik]|alles bis vor <zeit> wobei\n"
870 " <zeit> = [<n> d|tage] [<n> h|stunden] [<n> m|min|minuten]\n"
871 " uebergehe thread|antworten (entspr. 'ignoriere thread')\n");
872
873 return 1;
874}
875
876
877static int UncatchupSyntax()
878{
879 notify_fail(
880 "Syntax: wiederhole <anz> [artikel]\n"
881 " wiederhole [ab vor] [<anz> m|minute[n]] [<anz> h|stunde[n]] [<anz> d|tag[e]]\n"
882 " wiederhole ab tag.monat[.jahr]\n"
883 " wiederhole alles\n"
884 "Der wiederhole- oder uncatchup-Befehl bezieht sich immer auf die aktuelle\n"
885 "Rubrik und markiert die angegebenen Artikel wieder als ungelesen.\n"
886 "Zeiten (2. Syntax) sind rueckwaerts ab aktueller Uhrzeit gerechnet.\n"),0;
887 return 0;
888}
889
890
891static Uncatchup(string str)
892{
893 mixed args;
894 int i,zeit;
895 int mode; // 0 = nix, 1=Anzahl Artikel, 2=Zeit, 3=alles
896
897 str=this_player()->_unparsed_args(); // wg. Datum
898 if ( !TP || !str || !stringp(str) || str=="?" || str=="-?" )
899 return UncatchupSyntax();
900
901 if (!pointerp(NEWSSERVER->GetNotes(GROUP)))
902 return notify_fail("Seltsam, die Rubrik '"+GROUP+
903 "' gibt es nicht mehr...\n"), 0;
904
905 args=({""})+explode(lower_case(str)," ");
906 if (args[1]=="ab") {
907 mode=2;
908 if (sizeof(args)<3)
909 return UncatchupSyntax();
910 zeit=InterpretTime(args[2..]);
911 } else {
912 zeit=time();
913 for (i=sizeof(args)-1;i>0;i--) {
914 switch(args[i]){
915 case "alles":
916 case "alle":
917 case "all":
918 if (mode&&mode!=3) return
919 notify_fail("Bitte nur Zeit ODER alles ODER Anzahl angeben!\n"),0;
920 mode=3;
921 break;
922 case "minuten":
923 case "minute":
924 case "m":
925 case "stunden":
926 case "stunde":
927 case "h":
928 case "tage":
929 case "tag":
930 case "d":
931 if (mode&&mode!=2) return
932 notify_fail("Bitte nur Zeit/Datum ODER alles ODER "
933 "Anzahl angeben!\n"),0;
934 mode=2;
935 zeit-=(((args[i][0]=='m') ? 60 :
936 ((args[i][0]=='s' || args[i][0]=='h') ? 3600 : 86400))
937 *to_int(args[i-1]));
938 i--;
939 break;
940 case "artikel":
941 if (mode&&mode!=1) return
942 notify_fail("Bitte nur Zeit/Datum ODER alles ODER "
943 "Anzahl angeben!\n"),0;
944 mode=1;
945 zeit=to_int(args[i-1]);
946 i--;
947 break;
948 case "ab":
949 return
950 notify_fail("Bitte nur Zeit/Datum ODER alles ODER "
951 "Anzahl angeben!\n"),0;
952 default:
953 if (!to_int(args[i]))
954 return notify_fail("Unbekanntes Argument '"+args[i]+
955 "'! Aktion abgebrochen.\n"),0;
956 if (mode&&mode!=1) return
957 notify_fail("Bitte nur Zeit/Datum ODER alles ODER "
958 "Anzahl angeben!\n"),0;
959 mode=1;
960 zeit=to_int(args[i]);
961 }
962 }
963 }
964
965 switch(mode){
966 case 0:
967 return notify_fail("Gib bitte irgendeine Einheit an "
968 "(Hilfe mit wiederhole -?)!\n");
969 case 2:
970 read_until[GROUP]=(read_until[GROUP]>=0)?zeit:-zeit;
971 write(break_string("Markiere alle Artikel in Rubrik "+GROUP+
972 " seit "+dtime(zeit)+" als ungelesen.\n",78));
973 break;
974 case 3:
975 read_until[GROUP]=(read_until[GROUP]>=0?1:-1);
976 write("Markiere die komplette Rubrik "+GROUP+" als ungelesen.\n");
977 break;
978 case 1:
979 write(break_string("Markiere die letzten "+zeit+
980 " gelesenen Artikel in Rubrik "+GROUP+" als ungelesen.\n",78));
981 { int h; mixed notes;
982 notes=NEWSSERVER->GetNotes(GROUP);
983 h=sizeof(notes)-1;
984 while ( (h>=0) && (abs(read_until[GROUP]) < notes[h][M_TIME]) ) {
985 h--;
986 }
987 if (h==-1||h<zeit)
988 read_until[GROUP]=
989 (read_until[GROUP]>=0)?1:-1;
990 else
991 read_until[GROUP]=(
992 (read_until[GROUP]>=0)?notes[h-zeit][M_TIME]
993 :-notes[h-zeit][M_TIME]);
994 }
995 }
996 write("Ok. Du kannst die als ungelesen markierten Artikel "
997 "mit nn nochmal lesen.\n");
998
999 if (TP) TP->SetProp(P_READ_NEWS,read_until);
1000 return 1;
1001}
1002
1003
Zesstra@Morgengrauen4090ca62016-07-19 00:22:34 +02001004mapping QueryRead() {
1005 return read_until;
MG Mud User88f12472016-06-24 23:31:02 +02001006}
1007
Zesstra@Morgengrauen4090ca62016-07-19 00:22:34 +02001008static int CatchNewsError(int err,string text4minus3) {
MG Mud User88f12472016-06-24 23:31:02 +02001009 switch (err) {
1010 case 1: return 1;
1011 case -1: write("Du darfst in dieser Rubrik nicht schreiben!\n"); return 0;
1012 case -2: write("Die Rubrik gibt es nicht mehr, sehr seltsam...\n"); return 0;
1013 case -3: write(text4minus3+"\n"); return 0;
1014 default: write("Interner Fehler "+err+", Erzmagier verstaendigen!\n"); return 0;
1015 }
Zesstra66b76672016-08-31 22:43:33 +02001016 return 0;
MG Mud User88f12472016-06-24 23:31:02 +02001017}
1018
Zesstra@Morgengrauen4090ca62016-07-19 00:22:34 +02001019static varargs int schreib(string str,string pretext,int called_by_itself,
1020 string statuslines)
1021{
MG Mud User88f12472016-06-24 23:31:02 +02001022 int err;
1023
1024 if (str=="?"||str=="-?") {
1025 write("Syntax: schreib <Titel>\n"
1026 " beginnt einen neuen Artikel in der Zeitung.\n");
1027 return 1;
1028 }
1029
1030 if (!this_interactive() || !this_interactive()->query_real_name()) return 0;
1031 if (!called_by_itself && extern_call() && !pretext)
1032 str=this_interactive()->_unparsed_args()||"";
1033 if (called_by_itself && str=="~q") {
1034 write("Abgebrochen.\n");
1035 return 1;
1036 }
1037 if (!CatchNewsError(
1038 NEWSSERVER->AskAllowedWrite(GROUP),
1039 "Diese Rubrik ist leider schon randvoll!")) return 1;
1040 if (!called_by_itself)
1041 write("Neuer Artikel in Rubrik "+GROUP+":\n");
1042 if (!str || str=="" || str=="artikel") {
1043 input_to("schreib", INPUT_PROMPT, "Titel des Artikels: ", pretext,1);
1044 return 1;
1045 }
1046 // writer=this_interactive()->query_real_name();
1047 message=allocate(6);
1048 message[M_BOARD]=GROUP;
1049 message[M_TITLE]=killctrl(str);
1050 message[M_MESSAGE]=statuslines;
1051 write("Titel ist: "+str+".\n\
1052Gib jetzt Deinen Text ein,\n\
1053** oder . wenn Du fertig bist, ~q zum Abbrechen, ~h fuer eine Hilfsseite.\n");
1054 nedit("PostNote",pretext);
1055 return 1;
1056}
1057
1058static varargs Reply(string str,string newtitle) {
1059 mixed dummy,replytitle,s;
1060 int nr;
1061
1062 if ((dummy=(str||newtitle))=="?"||dummy=="-?") {
1063 write("Der Antworte-Befehl ist doppelt belegt.\n"
1064 "1. (Zeitung): Schreibe Antwort auf einen Artikel in der Zeitung.\n"
1065 " Syntax: antworte\n"
1066 " antworte auf artikel <nr> [neuer Titel]\n"
1067 " reply [auf artikel <nr> | to note <nr>] [neuer Titel]\n"
1068 "2. aehnlich 'sage':\n"
1069 " Du tippst zum Beispiel:\n"
1070 " antworte ja, das weiss ich\n"
1071 " Alle Spieler im Raum sehen dann:\n"
1072 " <Dein Name> antwortet: ja, das weiss ich.\n"
1073 "Bitte beachte, dass jede Syntax, die auf den antworte-Befehl der "
1074 "Zeitung\npasst, auch von der Zeitung ausgewertet wird.\n");
1075 return 1;
1076 }
1077
1078 if (str&&
1079 ((sscanf(lower_case(str),"auf artikel %d",dummy)==1 &&
1080 str=this_player()->_unparsed_args()[12..])||
1081 (sscanf(lower_case(str),"to note %d",dummy)==1 &&
1082 str=this_player()->_unparsed_args()[8..]))) {
1083 mixed notes;
1084 notes=NEWSSERVER->GetNotes(GROUP);
1085 if (dummy<1||dummy>sizeof(notes))
1086 return write("Einen Artikel mit der Nummer "+dummy+
1087 " gibt es in dieser Rubrik nicht.\n"),1;
1088 dummy--;
1089 replytitle=({notes[dummy][M_TITLE],notes[dummy][M_WRITER],
1090 notes[dummy][M_TIME],GetTID(notes[dummy]),GROUP});
1091 DEBUGVAR(str);
1092 if (!newtitle&&str&&sizeof(str)&&sscanf(str,"%d %s",dummy,str)==2)
1093 newtitle=str;
1094 }
1095 else if (!str||!sizeof(str)) {
1096 if (!lasttitle) return
1097 write("Du hast noch gar nichts gelesen, worauf Du "
1098 "antworten koenntest.\n"),1;
1099 replytitle=lasttitle;
1100 }
1101 else return 0;
1102
1103// return ComposeReply(replytitle);
1104//}
1105//
1106//
1107//ComposeReply(mixed replytitle) {
1108
1109 if (!newtitle) {
1110 if (replytitle[0][0..7]=="Re: Re: ") newtitle="Re^3: "+replytitle[0][8..];
1111 else if (sscanf(replytitle[0],"Re^%d: %s",nr,newtitle))
1112 newtitle="Re^"+(nr+1)+": "+newtitle;
1113 else newtitle="Re: "+replytitle[0];
1114 }
1115 return schreib(newtitle,0,0,
1116 STATUSESCAPE+" rn="+replytitle[LAST_WRITER]+
1117 " rt="+replytitle[LAST_TIME]+
1118 " rg="+replytitle[LAST_GROUP]+"\n"+
1119 STATUSESCAPE+" tid="+replytitle[LAST_TID]+"\n");
1120}
1121
1122static Reply2(str) {
1123 str = this_player()->_unparsed_args();
1124 if (!str||str[0..11]=="auf artikel "||str[0..7]=="to note ")
1125 return Reply(str);
1126 return Reply(0,str);
1127}
1128
1129static void InformPlayers(string group,string player,string text)
1130{
1131 object *players;
1132 int i;
1133 mixed data;
1134 string ig;
1135
1136 players=users();
1137 ig=lower_case(player)+".news";
1138 for (i=sizeof(players)-1;i>=0;i--) {
1139 data=players[i]->QueryProp(P_WAITFOR);
1140 if (pointerp(data)&&(member(data,"Mpa")>-1)) {
1141 data=players[i]->QueryProp(P_READ_NEWS);
1142 if (mappingp(data)&&(data[group]>0)) {
1143 data=players[i]->QueryProp(P_IGNORE);
1144 if ((!pointerp(data))||(member(data,ig)==-1))
1145 tell_object(players[i],text);
1146 }
1147 }
1148 }
1149}
1150
1151static PostNote(text) {
1152 int err;
1153 string sig;
1154
1155 if (!text) {
1156 write("Abbruch! Artikel landet im Reisswolf.\n");
1157 return 1;
1158 }
1159 if (!sizeof(old_explode(text,"\n")-
1160 ({"q","quit"," **","** ","ende","","exit"," "})
1161 ) )
1162 return write("\
1163ACHTUNG: Wolltest Du wirklich einen Artikel ohne Inhalt in die mpa setzen?\n\
1164Artikel ohne erkennbaren Inhalt werden NICHT veroeffentlicht. Bitte ueber-\n\
1165pruef Deine Syntax, falls Du keinen Artikel schreiben wolltest, oder schreib\n\
1166auch ein bisschen Text!\n\
1167Artikel landet im Reisswolf.\n"),1;
1168 if (!message[M_MESSAGE])
1169 message[M_MESSAGE] = text;
1170 else
1171 message[M_MESSAGE]+=text;
1172 if (sig=read_file("/players/"+geteuid(this_interactive())+"/.signature"))
1173 message[M_MESSAGE]+=sig;
1174 if (!CatchNewsError(NEWSSERVER->WriteNote(message),
1175 "Diese Rubrik ist voll. Mist, da war jemand schneller...")) {
1176 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");
1177 return 0;
1178 }
1179 write("OK, Artikel ist veroeffentlicht.\n");
1180 say(capitalize(TP->name())+
1181 " hat einen Artikel in der Zeitung veroeffentlicht.\n");
1182 if (geteuid(TP)!="sitopanaki")
1183 InformPlayers(message[M_BOARD],geteuid(this_interactive()),
1184 "* MPA: Neuer Artikel von "+
1185 capitalize(geteuid(this_interactive()))+
1186 " in Rubrik \""+message[M_BOARD]+"\".\n");
1187 message=0; /* Platz sparen! */
1188 return 1;
1189}
1190
1191
1192//static // allowing aliasing *Rumata* 5/8/96
1193inhalt(str) {
1194 int i,endflag,timeout;
1195 string *gruppen,s,txt,suche;
1196 mixed messages;
1197
1198 if (str=="?"||str=="-?") return
1199 write("Syntax: inhalt [<rubrik>] [ende] [suche <text>]\n"),1;
1200
1201 str=(!str)?({}):explode(str," ");
1202
1203 if (sizeof(str) && (str[0]=="neu" || str[0]=="neues") )
1204 return ReadNextUnread("liste"),1;
1205
1206 if (endflag=member(str,"ende")+1) str-=({"ende"});
1207 if (((i=member(str,"suche")) != -1) && (sizeof(str) > i)) {
1208 suche=lower_case(implode(str[i+1..]," "));
1209 str=str[0..i-1];
1210 }
1211 else
1212 suche=0;
1213 if (!sizeof(str)) {
1214 str=GROUP;
1215 if (!pointerp(messages=NEWSSERVER->GetNotes(str))){
1216 str=GROUP=DEFAULTGROUP;
1217 if (!pointerp(messages=NEWSSERVER->GetNotes(str)))
1218 return notify_fail("Seltsam, irgendwie geht hier einiges schief...\n"),0;
1219 }
1220 }
1221 else {
1222 str=GetGroupName(str[0]);
1223 if (!str) return 1;
1224 messages=NEWSSERVER->GetNotes(str);
1225 }
1226 timeout=abs(read_until[str]);
1227 s="Inhalt der Rubrik "+str+":\n\n";
1228 if (!pointerp(messages) || !sizeof(messages))
1229 return
1230 write(s+"Zur Zeit befinden sich keine Artikel in dieser Rubrik.\n"),1;
1231 if (suche)
1232 s+="Suche nach '"+suche+"' in der Rubrik ergab folgende Treffer:\n\n";
1233 else
1234 if (sizeof(messages)==1)
1235 s+="Zur Zeit befindet sich ein Artikel in der Rubrik:\n\n";
1236 else
1237 s+="Zur Zeit befinden sich "+sizeof(messages)+
1238 " Artikel in der Rubrik:\n\n";
1239 if (endflag&&(sizeof(messages)>16)&&
1240 messages[sizeof(messages)-16][M_TIME]>=timeout) timeout=-1;
1241 for (i=(endflag?(((endflag=sizeof(messages)-15)<0)?0:endflag):0);
1242 i<sizeof(messages);i++)
1243 {
1244 txt=sprintf("%2d.%s%-48s%4d (%-11s) %s\n",i+1,
1245 (((timeout>=0) && timeout<messages[i][M_TIME] )?
1246 ( (timeout=-1),"*"):" "),messages[i][M_TITLE],
1247 sizeof(explode(messages[i][M_MESSAGE],"\n")),
1248 messages[i][M_WRITER],
1249 dtime(messages[i][M_TIME])[5..11]);
1250 if (!suche || (strstr(lower_case(txt), suche) != -1))
1251 s+=txt;
1252 }
1253 if (endflag) write(s);
1254 else this_player()->More(s);
1255 return 1;
1256}
1257
1258
1259static artikel(str) {
1260 return lies(str);
1261}
1262
1263
Zesstra@Morgengrauen795a0e12016-07-19 00:17:42 +02001264static int loesche(string str) {
MG Mud User88f12472016-06-24 23:31:02 +02001265 int num;
1266 mixed *messages;
1267
1268 if (str=="?"||str=="-?") return
1269 write("Syntax: loesche artikel <nr>\n"
1270 " (bezieht sich immer auf die aktuelle Rubrik.\n"),1;
1271
1272 if (!str || sscanf(str,"artikel %d",num)!=1 || num<=0)
1273 return notify_fail("WELCHEN Artikel willst Du loeschen ?\n"),0;
1274 num--;
1275 messages=(NEWSSERVER->GetNotes(GROUP));
1276 if (sizeof(messages)<=num) return
1277 notify_fail("So viele Artikel sind da nicht!\n"),0;
1278
1279 write("Rubrik "+GROUP+", Artikel "+(num+1)+
1280 " von "+capitalize(messages[num][M_WRITER])+
1281 " vom "+dtime(messages[num][M_TIME])[5..26]+
1282 ",\nTitel: "+messages[num][M_TITLE]+",\n\n");
1283
1284 /* (ueberfluessige Abfrage, macht schon /secure/news)
1285 if (!IS_LEARNER(TI) && lower_case(messages[num][M_WRITER])!=geteuid(TI))
1286 return
1287 write("Nicht geloescht - du darfst nur eigene Artikel loeschen.\n"),1;
1288 */
1289
1290 switch (NEWSSERVER->RemoveNote(GROUP, num)){
1291 case 1: write("Artikel ist geloescht.\n");
1292 say(this_player()->name()+" loescht einen Artikel aus der Zeitung.\n");
1293 return 1;
1294 case -1: write("Diesen Artikel darfst Du nicht loeschen.\n");
1295 say(this_player()->name()+" versucht vergeblich, einen Artikel zu loeschen.\n");
1296 return 1;
1297 case -3: write("So viele Artikel sind da nicht !\n");
1298 return 1;
1299 default: write("Interner Fehler. Bitte Erzmagier verstaendigen !\n");
1300 return 1;
Zesstra@Morgengrauen4090ca62016-07-19 00:22:34 +02001301 }
1302 return 0;
MG Mud User88f12472016-06-24 23:31:02 +02001303}
1304
1305// Low-level Funktion zum Abonnieren/Abbestellen von Rubriken
1306// bestellen==0 -> abbestellen, bestellen!=0 -> bestellen
1307// Rueckgabe: 0, wenn der gewuenschte Zustand schon eingestellt war, sonst 1
1308private int _subscribe(string groupname, int bestellen) {
1309
1310 int timeout = read_until[groupname];
1311 // gar nicht abonniert/abbestellt?
1312 if (!bestellen && timeout < 0)
1313 return 0;
1314 else if (bestellen && timeout > 0)
1315 return 0;
1316
1317 // wenn noch kein timeout, erstmal auf 1 setzen
1318 timeout ||= 1;
1319
1320 // -1 fuer abbestellen, +1 fuer bestellen
1321 if (bestellen)
1322 read_until[groupname] = abs(timeout);
1323 else
1324 read_until[groupname] = -timeout;
1325
1326 if (environment())
1327 environment()->SetProp(P_READ_NEWS, read_until);
1328
1329 return 1;
1330}
1331
1332static Unsubscribe(str) {
1333 int timeout;
1334 if (str=="?"||str=="-?") return
1335 write("Syntax: unsubscribe <rubrik>"
1336 " oder: bestelle <rubrik> ab\n"),1;
1337 str=GetGroupName(str);
1338 if (!str) return 1;
1339 if (!_subscribe(str,0)) {
1340 notify_fail("Die Rubrik hast Du gar nicht abonniert!\n");
1341 return 0;
1342 }
1343 else {
1344 write("Rubrik "+str+" abbestellt.\n");
1345 }
1346 return 1;
1347}
1348
1349
1350static Bestelle(str) { /* ab ! */
1351 if (!str || !sscanf(str,"%s ab",str)) return _notify_fail(
1352 "Die Syntax ist: 'bestelle <rubrik> ab', "
1353 "oder meinst Du 'abonniere'?\n"),0;
1354 return Unsubscribe(str);
1355}
1356
1357static Subscribe(str) {
1358 int timeout;
1359 if (str=="?"||str=="-?") return
1360 write("Syntax: abonniere <rubrik>\n"
1361 " oder: subscribe <rubrik>\n"),1;
1362 str=GetGroupName(str);
1363 if (!str) return 1;
1364 if (!_subscribe(str,1)) {
1365 notify_fail("Die Rubrik hast Du doch schon abonniert!\n");
1366 return 0;
1367 }
1368 else {
1369 write("Rubrik "+str+" abonniert.\n");
1370 }
1371 return 1;
1372}
1373
1374// Legt die anfaenglichen Abonnements eines Neulesers fest und bestellt alle
1375// anderen ab.
1376private void InitialSubscriptions() {
1377 // alle abbestellen. ;-)
1378 // Alternative: fuer alle _subscribe(,0) rufen
1379 if (!query_once_interactive(environment()))
1380 return;
1381 string *gruppen = NEWSSERVER->GetGroups();
1382 int *vals = allocate(sizeof(gruppen),-1);
1383 read_until = mkmapping(gruppen,vals);
1384
1385 // jetzt die vorausgewaehlten bestellen
1386 foreach(string gruppe : INITIAL_SUBSCRIPTIONS) {
1387 if (member(gruppen, gruppe) > -1)
1388 _subscribe(gruppe,1);
1389 }
1390 // und ggf. noch die eigene Gildenrubrik
1391 string gilde = environment()->QueryProp(P_GUILD);
1392 if (stringp(gilde)
1393 && member(gruppen, "gilden."+gilde) > -1)
1394 _subscribe("gilden."+gilde,1);
1395
1396 environment()->SetProp(P_READ_NEWS, read_until);
1397}
1398
1399static MoveMessage(str) {
1400 int num,i;
1401 mixed msg/*,expl*/;
1402 string gr;
1403 if (str=="?"||str=="-?") return
1404 write("Syntax: verlege artikel <nr> nach <rubrik>\n"
1405 " Artikel und Rubrik muessen explizit angegeben werden.\n"),1;
1406 if (!str || sscanf(str,"artikel %d nach %s",num,gr)!=2) return (int)notify_fail(
1407 "verlege artikel <nr> nach <rubrik>, oder was?\n");
1408 if (!(gr=GetGroupName(gr))) return 1;
Zesstra@Morgengrauen0e0ac492016-07-19 00:13:51 +02001409 if (gr == GROUP)
1410 {
1411 write("Das waere reichlich sinnlos, nicht wahr?\n");
1412 return 1;
1413 }
MG Mud User88f12472016-06-24 23:31:02 +02001414 if (!(CatchNewsError(NEWSSERVER->AskAllowedWrite(gr),"Die Rubrik ist leider voll.\n"))) return 1;
1415
1416 if (!pointerp(msg=NEWSSERVER->GetNotes(GROUP)))
1417 return notify_fail("Seltsam, die Rubrik '"+GROUP+
1418 "' gibt es nicht mehr...\n"), 0;
1419
1420 num--;
1421 if (sizeof(msg)<=num) return
1422 notify_fail("So viele Nachrichten sind da nicht !\n"),0;
1423 msg=msg[num];
1424 if (geteuid(TI) != lower_case(msg[M_WRITER])) {
1425 if (!IS_LEARNER(TI)) return
1426 write("Du darfst nur Deine eigenen Artikel verlegen.\n"),1;
1427 write("WARNUNG: Das ist nicht Dein eigener Artikel!\n");
1428 }
1429 // return (int)notify_fail("Man darf zur Zeit nur eigene Artikel verlegen.\n");
1430 if (!CatchNewsError(NEWSSERVER->RemoveNote(GROUP,num),"Dieser Fehler kann eigentlich nicht auftreten"))
1431 write("Warnung! Konnte Artikel an alter Position nicht loeschen.\n");
1432 else write("Artikel von Rubrik "+GROUP+" entfernt.\n");
1433
1434 msg[M_MESSAGE]=
1435 sprintf("%s on=%s ot=%d og=%s\n",
1436 STATUSESCAPE,msg[M_WRITER],msg[M_TIME],msg[M_BOARD])
1437 +msg[M_MESSAGE];
1438
1439/*
1440 expl=explode(msg[M_MESSAGE],"\n");
1441 for (i=0;(IS_STATUSLINE(expl[i][0..2]));i++);
1442 msg[M_MESSAGE]=( (i) ? implode(expl[0..i-1],"\n")+"\n" : "" ) +
1443 "[Verlegt von "+msg[M_BOARD]+", "+msg[M_WRITER]+", "+
1444 dtime(msg[M_TIME])[5..26]+"]:\n"+
1445 implode(expl[i..],"\n")+"\n";
1446*/
1447
1448 msg[M_BOARD]=gr;
1449 NEWSSERVER->WriteNote(msg);
1450 write("Artikel nach Rubrik "+gr+" verlegt.\n");
1451 return 1;
1452}
1453
1454static MoveTrash()
1455{
1456 if (!pointerp(lasttitle)||sizeof(lasttitle)<LAST_SIZEOF) return
1457 write("Was denn bitte? Du hast noch gar nichts gelesen!\n"),1;
1458 if (lasttitle[LAST_GROUP]!=GROUP) return
1459 write("Nix gibts! Du hast die Rubrik gewechselt!\n"),1;
1460 return MoveMessage(sprintf("artikel %d nach muell",lasttitle[LAST_NR]+1));
1461}
1462
1463static SaveMessage(str) {
1464 mixed num;
1465 mixed *messages;
1466
1467 if (intp(str)) num=str;
1468 if ((!num && (!str || str=="" || sscanf(str,"artikel %d",num)!=1)) || num<=0) {
1469 notify_fail("Welchen Artikel willst Du abspeichern?\n");
1470 return 0;
1471 }
1472 if (!pointerp(messages=NEWSSERVER->GetNotes(GROUP)))
1473 return notify_fail("Seltsam, die Rubrik '"+GROUP+
1474 "' gibt es nicht mehr...\n"), 0;
1475 num--;
1476 if (sizeof(messages)<=num) {
1477 notify_fail("So viele Nachrichten sind da nicht !\n");
1478 return 0;
1479 }
1480 if(write_file(SAVEMSGPATH(TP),Message2string(num,messages,M2S_REMOTE)+"\n"))
1481 write(break_string(
1482 "Inhalt des Artikels wurde nach "+SAVEMSGPATH(TP)+" gespeichert.\n"));
1483 else
1484 write(break_string(
1485 "Fehler beim Schreiben nach "+SAVEMSGPATH(TP)+"!\n"));
1486 return 1;
1487}
1488
1489
1490static MailMessage(str) {
1491 mixed num,rec,group;
1492 mixed *messages;
1493
1494// printf("%O\n",inherit_list(environment(TP)));
1495// if (member(query_actions(this_player()),"mail")<0)
1496// tut nicht wegen anderer Implemtierung von AddCmd in Raeumen
1497
1498 if (str=="?"||str=="-?") return
1499 write("Syntax: versende artikel <nr> an <adresse>\n"),1;
1500
1501 str=TP->_unparsed_args(); // wegen Mailadressen
1502 if (str) str=lower_case(str);
1503
1504 if (!IS_SEER(TP) && !IS_POST(environment(TP)))
1505 return notify_fail("Du musst in ein Postamt gehen, "
1506 "um etwas versenden zu koennen.\n"),0;
1507
1508 num=0;
1509
1510 if (!str || (sscanf(str,"artikel %d an %s",num,rec)!=2 &&
1511 sscanf(str,"note %d to %s",num,rec)!=2 &&
1512 sscanf(str,"note to %s",rec)!=1 &&
1513 sscanf(str,"artikel an %s",rec)!=1)){
1514 if (!str || str[0..6]=="artikel"||str[0..3]=="note") return
1515 write("Welchen Artikel willst Du versenden, und wohin?\n"),1;
1516 else return
1517 notify_fail("Welchen Artikel willst Du versenden, und wohin?\n"),0;
1518 }
1519 if (!num&&(!pointerp(lasttitle)||sizeof(lasttitle)<LAST_SIZEOF))
1520 return write("Du hast scheinbar noch nichts gelesen, worauf man sich "
1521 "beziehen kann.\nGib notfalls die Nummer des Artikels an.\n"),1;
1522
1523 // printf("lasttitle= %O\nnum=%d\n",lasttitle,num);
1524
1525 if (!pointerp(messages=
1526 NEWSSERVER->GetNotes(group=(num?GROUP:lasttitle[LAST_GROUP]))))
1527 return notify_fail("Seltsam, die Rubrik gibt es nicht mehr...\n"), 0;
1528
1529 if (!pointerp(messages)||!sizeof(messages))
1530 return write("Die Rubrik "+group+" ist leer.\n"),1;
1531 if (num<0||sizeof(messages)<num) return
1532 write("Einen Artikel mit Nummer "+num+" gibt es in Rubrik "+group+
1533 " nicht!\n"),1;
1534
1535 if (num) num--;
1536 else {
1537 int h;
1538 num=-1;
1539 if (pointerp(messages)) {
1540 for (h=sizeof(messages)-1;
1541 (h>=0 && messages[h][M_TIME]>=lasttitle[LAST_TIME]);h--)
1542 if (messages[h][M_TIME]==lasttitle[LAST_TIME] &&
1543 lower_case(messages[h][M_WRITER])==
1544 lower_case(lasttitle[LAST_WRITER]))
1545 num=h;
1546 }
1547 if (num<0)
1548 return notify_fail("Konnte Artikel nicht wiederfinden, "
1549 "bitte gib die Nummer an.\n"),0;
1550 }
1551 MAILER->do_mail( rec,
1552 "MPA: "+messages[num][M_TITLE]+" ("+messages[num][M_WRITER]+")",
1553 Message2string(num,messages,M2S_REMOTE,group)+"\n");
1554 return 1;
1555}
1556
1557
1558
1559HelpPage(str) {
1560 if (str!="mpa"&&str!="zeitung") return 0;
1561 this_player()->More(read_file(HELPPAGE)+
1562 (IS_LEARNER(TP) ? read_file(WIZHELPPAGE) : ""));
1563 return 1;
1564}
1565
1566/*--------------------------------------------------------------------------*/
1567
1568protected void NotifyMove(object dest, object oldenv, int method) {
1569 ::NotifyMove(dest, oldenv, method);
1570
1571 // P_READ_NEWS aus dem Spieler holen.
1572 if (objectp(environment()) && query_once_interactive(environment())) {
1573 read_until=environment()->QueryProp(P_READ_NEWS);
1574 }
1575
1576 if (!mappingp(read_until) || !sizeof(read_until))
1577 InitialSubscriptions();
1578}
1579
1580int GetTID(mixed message) {
1581 string dummy;
1582 int tid;
1583 return (sscanf(message[M_MESSAGE],"%s" STATUSESCAPE " tid=%d",dummy,tid)==2)
1584 ? tid : message[M_TIME];
1585}
1586