blob: c27f8277d654e720999f990220cf38c1fbf01ef9 [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 }
755 else return write("Argumentfehler.\n"),0;
756}
757
758static Catchup(string str)
759{
760 int welche,zeit,i;
761 string gr;
762 mixed groups,news,args;
763
764 if (!pointerp(NEWSSERVER->GetNotes(GROUP)))
765 return notify_fail("Seltsam, die Rubrik '"+GROUP+
766 "' gibt es nicht mehr...\n"), 0;
767
768 str=this_player()->_unparsed_args(); // wg. Datum
769 if (str) str=lower_case(str);
770 else str=GROUP; // default: aktuelle Rubrik komplett.
771
772 if (str=="?"|| str=="-?") return CatchupSyntax();
773
774 // uebergehe Antworten (Thread ignorieren)
775 if (str&&(str[0..6]=="antwort"||str=="thread")) {
776 if (!pointerp(lasttitle)) return
777 write("Du hast bisher noch keinen Artikel gelesen, damit kann ich nicht wissen,\nwelchen Thread du uebergehen willst.\n"),1;
778 if (!read_until[IGNOREGROUP]) read_until[IGNOREGROUP]=([]);
779 if (!read_until[IGNOREGROUP][GROUP]) read_until[IGNOREGROUP][GROUP]=([]);
780 if (read_until[IGNOREGROUP][GROUP][lasttitle[3]]) {
781 read_until[IGNOREGROUP][GROUP]=m_copy_delete(read_until[IGNOREGROUP][GROUP],lasttitle[3]);
782 write("Dieser Thread wird jetzt nicht mehr uebergangen.\n");
783 } else {
784 read_until[IGNOREGROUP][GROUP][lasttitle[3]]=lasttitle[2];
785 write("Dieser Thread wird ab sofort uebergangen.\nFalls das ein Irrtum war, wiederhole den Befehl augenblicklich.\n");
786 }
787 if (TP) TP->SetProp(P_READ_NEWS,read_until);
788 return 1;
789 }
790
791 groups=NEWSSERVER->GetGroups();
792
793 args=explode(str," ");
794
795 // Uebergehe alles
796
797 if (args[0]=="alle" || args[0]=="alles" || args[0]=="all") {
798 if (sizeof(args)<=1) zeit=time()-1;
799 else if (args[1]!="bis") return CatchupSyntax();
800 else if (sizeof(args)<3) return CatchupSyntax();
801
802 else zeit=InterpretTime(args[2..],1);
803 if (zeit>time()) zeit=time()-1;
804 write("Uebergehe alle Rubriken bis "+dtime(zeit)+".\n");
805 for (welche=0;welche<sizeof(groups);++welche) {
806 gr=groups[welche];
807// zeit=NEWSSERVER->GetNewsTime(gr);
808 if (abs(read_until[gr])<zeit)
809 read_until[gr]=(read_until[gr]>=0)?zeit:-zeit;
810 if (TP) TP->SetProp(P_READ_NEWS,read_until);
811 }
812 return 1;
813 }
814
815 // Anzahl Artikel
816
817 if (sizeof(args)>=2 && args[1]=="artikel") {
818 if (!to_int(args[0])) return CatchupSyntax();
819 news=NEWSSERVER->GetNotes(GROUP);
820 for (i=sizeof(news)-1;i>=0&&news[i][M_TIME]>read_until[GROUP];i--);
821 welche=i+to_int(args[0]);
822 if (welche>=sizeof(news)) welche=sizeof(news)-1;
823 write("Uebergehe die naechsten "+(welche-i)+" Artikel in Rubrik "+
824 GROUP+"\n.");
825 if (welche>=0) {
826 zeit=news[welche][M_TIME];
827 read_until[GROUP]=(read_until[GROUP]>=0)?zeit:-zeit;
828 if (TP) TP->SetProp(P_READ_NEWS,read_until);
829 }
830 return 1;
831 }
832
833 // einzelne Rubrik.
834
835 if (!(gr=GetGroupName(args[0]))) return 1;
836 news=NEWSSERVER->GetNotes(gr);
837 if (!sizeof(news)) {
838 write("Rubrik "+gr+" ist leer.\n");
839 return 1;
840 }
841// zeit=news[sizeof(news)-1][M_TIME];
842 if (sizeof(args)<=1)
843 zeit=time();
844 else
845 if (args[1]!="bis") return CatchupSyntax();
846 else
847 zeit=InterpretTime(args[2..],1);
848 if (zeit>time()) zeit=time();
849 read_until[gr]=zeit;
850 if (TP) TP->SetProp(P_READ_NEWS,read_until);
851 write("Uebergehe "+gr+" bis "+dtime(zeit)+",\nletzter Artikel war vom "+
852 dtime(NEWSSERVER->GetNewsTime(gr))+"\n");
853 return 1;
854}
855
856
857static Ignore(str) {
858 if (str=="thread"||str=="antworten") return Catchup(str);
859 return 0;
860}
861
862static CatchupSyntax() {
863 write("Syntax des Befehls uebergehe (oder catchup):\n"
864 " uebergehe [rubrik] (default: aktuelle Rubrik)\n"
865 " uebergehe alles (in allen Rubriken)\n"
866 " uebergehe <anz> artikel (in akt. Rubrik)\n"
867 " uebergehe [rubrik]|alles bis <tag>.<monat>.[<jahr>]\n"
868 " uebergehe [rubrik]|alles bis vor <zeit> wobei\n"
869 " <zeit> = [<n> d|tage] [<n> h|stunden] [<n> m|min|minuten]\n"
870 " uebergehe thread|antworten (entspr. 'ignoriere thread')\n");
871
872 return 1;
873}
874
875
876static int UncatchupSyntax()
877{
878 notify_fail(
879 "Syntax: wiederhole <anz> [artikel]\n"
880 " wiederhole [ab vor] [<anz> m|minute[n]] [<anz> h|stunde[n]] [<anz> d|tag[e]]\n"
881 " wiederhole ab tag.monat[.jahr]\n"
882 " wiederhole alles\n"
883 "Der wiederhole- oder uncatchup-Befehl bezieht sich immer auf die aktuelle\n"
884 "Rubrik und markiert die angegebenen Artikel wieder als ungelesen.\n"
885 "Zeiten (2. Syntax) sind rueckwaerts ab aktueller Uhrzeit gerechnet.\n"),0;
886 return 0;
887}
888
889
890static Uncatchup(string str)
891{
892 mixed args;
893 int i,zeit;
894 int mode; // 0 = nix, 1=Anzahl Artikel, 2=Zeit, 3=alles
895
896 str=this_player()->_unparsed_args(); // wg. Datum
897 if ( !TP || !str || !stringp(str) || str=="?" || str=="-?" )
898 return UncatchupSyntax();
899
900 if (!pointerp(NEWSSERVER->GetNotes(GROUP)))
901 return notify_fail("Seltsam, die Rubrik '"+GROUP+
902 "' gibt es nicht mehr...\n"), 0;
903
904 args=({""})+explode(lower_case(str)," ");
905 if (args[1]=="ab") {
906 mode=2;
907 if (sizeof(args)<3)
908 return UncatchupSyntax();
909 zeit=InterpretTime(args[2..]);
910 } else {
911 zeit=time();
912 for (i=sizeof(args)-1;i>0;i--) {
913 switch(args[i]){
914 case "alles":
915 case "alle":
916 case "all":
917 if (mode&&mode!=3) return
918 notify_fail("Bitte nur Zeit ODER alles ODER Anzahl angeben!\n"),0;
919 mode=3;
920 break;
921 case "minuten":
922 case "minute":
923 case "m":
924 case "stunden":
925 case "stunde":
926 case "h":
927 case "tage":
928 case "tag":
929 case "d":
930 if (mode&&mode!=2) return
931 notify_fail("Bitte nur Zeit/Datum ODER alles ODER "
932 "Anzahl angeben!\n"),0;
933 mode=2;
934 zeit-=(((args[i][0]=='m') ? 60 :
935 ((args[i][0]=='s' || args[i][0]=='h') ? 3600 : 86400))
936 *to_int(args[i-1]));
937 i--;
938 break;
939 case "artikel":
940 if (mode&&mode!=1) return
941 notify_fail("Bitte nur Zeit/Datum ODER alles ODER "
942 "Anzahl angeben!\n"),0;
943 mode=1;
944 zeit=to_int(args[i-1]);
945 i--;
946 break;
947 case "ab":
948 return
949 notify_fail("Bitte nur Zeit/Datum ODER alles ODER "
950 "Anzahl angeben!\n"),0;
951 default:
952 if (!to_int(args[i]))
953 return notify_fail("Unbekanntes Argument '"+args[i]+
954 "'! Aktion abgebrochen.\n"),0;
955 if (mode&&mode!=1) return
956 notify_fail("Bitte nur Zeit/Datum ODER alles ODER "
957 "Anzahl angeben!\n"),0;
958 mode=1;
959 zeit=to_int(args[i]);
960 }
961 }
962 }
963
964 switch(mode){
965 case 0:
966 return notify_fail("Gib bitte irgendeine Einheit an "
967 "(Hilfe mit wiederhole -?)!\n");
968 case 2:
969 read_until[GROUP]=(read_until[GROUP]>=0)?zeit:-zeit;
970 write(break_string("Markiere alle Artikel in Rubrik "+GROUP+
971 " seit "+dtime(zeit)+" als ungelesen.\n",78));
972 break;
973 case 3:
974 read_until[GROUP]=(read_until[GROUP]>=0?1:-1);
975 write("Markiere die komplette Rubrik "+GROUP+" als ungelesen.\n");
976 break;
977 case 1:
978 write(break_string("Markiere die letzten "+zeit+
979 " gelesenen Artikel in Rubrik "+GROUP+" als ungelesen.\n",78));
980 { int h; mixed notes;
981 notes=NEWSSERVER->GetNotes(GROUP);
982 h=sizeof(notes)-1;
983 while ( (h>=0) && (abs(read_until[GROUP]) < notes[h][M_TIME]) ) {
984 h--;
985 }
986 if (h==-1||h<zeit)
987 read_until[GROUP]=
988 (read_until[GROUP]>=0)?1:-1;
989 else
990 read_until[GROUP]=(
991 (read_until[GROUP]>=0)?notes[h-zeit][M_TIME]
992 :-notes[h-zeit][M_TIME]);
993 }
994 }
995 write("Ok. Du kannst die als ungelesen markierten Artikel "
996 "mit nn nochmal lesen.\n");
997
998 if (TP) TP->SetProp(P_READ_NEWS,read_until);
999 return 1;
1000}
1001
1002
Zesstra@Morgengrauen4090ca62016-07-19 00:22:34 +02001003mapping QueryRead() {
1004 return read_until;
MG Mud User88f12472016-06-24 23:31:02 +02001005}
1006
Zesstra@Morgengrauen4090ca62016-07-19 00:22:34 +02001007static int CatchNewsError(int err,string text4minus3) {
MG Mud User88f12472016-06-24 23:31:02 +02001008 switch (err) {
1009 case 1: return 1;
1010 case -1: write("Du darfst in dieser Rubrik nicht schreiben!\n"); return 0;
1011 case -2: write("Die Rubrik gibt es nicht mehr, sehr seltsam...\n"); return 0;
1012 case -3: write(text4minus3+"\n"); return 0;
1013 default: write("Interner Fehler "+err+", Erzmagier verstaendigen!\n"); return 0;
1014 }
Zesstra66b76672016-08-31 22:43:33 +02001015 return 0;
MG Mud User88f12472016-06-24 23:31:02 +02001016}
1017
Zesstra@Morgengrauen4090ca62016-07-19 00:22:34 +02001018static varargs int schreib(string str,string pretext,int called_by_itself,
1019 string statuslines)
1020{
MG Mud User88f12472016-06-24 23:31:02 +02001021 int err;
1022
1023 if (str=="?"||str=="-?") {
1024 write("Syntax: schreib <Titel>\n"
1025 " beginnt einen neuen Artikel in der Zeitung.\n");
1026 return 1;
1027 }
1028
1029 if (!this_interactive() || !this_interactive()->query_real_name()) return 0;
1030 if (!called_by_itself && extern_call() && !pretext)
1031 str=this_interactive()->_unparsed_args()||"";
1032 if (called_by_itself && str=="~q") {
1033 write("Abgebrochen.\n");
1034 return 1;
1035 }
1036 if (!CatchNewsError(
1037 NEWSSERVER->AskAllowedWrite(GROUP),
1038 "Diese Rubrik ist leider schon randvoll!")) return 1;
1039 if (!called_by_itself)
1040 write("Neuer Artikel in Rubrik "+GROUP+":\n");
1041 if (!str || str=="" || str=="artikel") {
1042 input_to("schreib", INPUT_PROMPT, "Titel des Artikels: ", pretext,1);
1043 return 1;
1044 }
1045 // writer=this_interactive()->query_real_name();
1046 message=allocate(6);
1047 message[M_BOARD]=GROUP;
1048 message[M_TITLE]=killctrl(str);
1049 message[M_MESSAGE]=statuslines;
1050 write("Titel ist: "+str+".\n\
1051Gib jetzt Deinen Text ein,\n\
1052** oder . wenn Du fertig bist, ~q zum Abbrechen, ~h fuer eine Hilfsseite.\n");
1053 nedit("PostNote",pretext);
1054 return 1;
1055}
1056
1057static varargs Reply(string str,string newtitle) {
1058 mixed dummy,replytitle,s;
1059 int nr;
1060
1061 if ((dummy=(str||newtitle))=="?"||dummy=="-?") {
1062 write("Der Antworte-Befehl ist doppelt belegt.\n"
1063 "1. (Zeitung): Schreibe Antwort auf einen Artikel in der Zeitung.\n"
1064 " Syntax: antworte\n"
1065 " antworte auf artikel <nr> [neuer Titel]\n"
1066 " reply [auf artikel <nr> | to note <nr>] [neuer Titel]\n"
1067 "2. aehnlich 'sage':\n"
1068 " Du tippst zum Beispiel:\n"
1069 " antworte ja, das weiss ich\n"
1070 " Alle Spieler im Raum sehen dann:\n"
1071 " <Dein Name> antwortet: ja, das weiss ich.\n"
1072 "Bitte beachte, dass jede Syntax, die auf den antworte-Befehl der "
1073 "Zeitung\npasst, auch von der Zeitung ausgewertet wird.\n");
1074 return 1;
1075 }
1076
1077 if (str&&
1078 ((sscanf(lower_case(str),"auf artikel %d",dummy)==1 &&
1079 str=this_player()->_unparsed_args()[12..])||
1080 (sscanf(lower_case(str),"to note %d",dummy)==1 &&
1081 str=this_player()->_unparsed_args()[8..]))) {
1082 mixed notes;
1083 notes=NEWSSERVER->GetNotes(GROUP);
1084 if (dummy<1||dummy>sizeof(notes))
1085 return write("Einen Artikel mit der Nummer "+dummy+
1086 " gibt es in dieser Rubrik nicht.\n"),1;
1087 dummy--;
1088 replytitle=({notes[dummy][M_TITLE],notes[dummy][M_WRITER],
1089 notes[dummy][M_TIME],GetTID(notes[dummy]),GROUP});
1090 DEBUGVAR(str);
1091 if (!newtitle&&str&&sizeof(str)&&sscanf(str,"%d %s",dummy,str)==2)
1092 newtitle=str;
1093 }
1094 else if (!str||!sizeof(str)) {
1095 if (!lasttitle) return
1096 write("Du hast noch gar nichts gelesen, worauf Du "
1097 "antworten koenntest.\n"),1;
1098 replytitle=lasttitle;
1099 }
1100 else return 0;
1101
1102// return ComposeReply(replytitle);
1103//}
1104//
1105//
1106//ComposeReply(mixed replytitle) {
1107
1108 if (!newtitle) {
1109 if (replytitle[0][0..7]=="Re: Re: ") newtitle="Re^3: "+replytitle[0][8..];
1110 else if (sscanf(replytitle[0],"Re^%d: %s",nr,newtitle))
1111 newtitle="Re^"+(nr+1)+": "+newtitle;
1112 else newtitle="Re: "+replytitle[0];
1113 }
1114 return schreib(newtitle,0,0,
1115 STATUSESCAPE+" rn="+replytitle[LAST_WRITER]+
1116 " rt="+replytitle[LAST_TIME]+
1117 " rg="+replytitle[LAST_GROUP]+"\n"+
1118 STATUSESCAPE+" tid="+replytitle[LAST_TID]+"\n");
1119}
1120
1121static Reply2(str) {
1122 str = this_player()->_unparsed_args();
1123 if (!str||str[0..11]=="auf artikel "||str[0..7]=="to note ")
1124 return Reply(str);
1125 return Reply(0,str);
1126}
1127
1128static void InformPlayers(string group,string player,string text)
1129{
1130 object *players;
1131 int i;
1132 mixed data;
1133 string ig;
1134
1135 players=users();
1136 ig=lower_case(player)+".news";
1137 for (i=sizeof(players)-1;i>=0;i--) {
1138 data=players[i]->QueryProp(P_WAITFOR);
1139 if (pointerp(data)&&(member(data,"Mpa")>-1)) {
1140 data=players[i]->QueryProp(P_READ_NEWS);
1141 if (mappingp(data)&&(data[group]>0)) {
1142 data=players[i]->QueryProp(P_IGNORE);
1143 if ((!pointerp(data))||(member(data,ig)==-1))
1144 tell_object(players[i],text);
1145 }
1146 }
1147 }
1148}
1149
1150static PostNote(text) {
1151 int err;
1152 string sig;
1153
1154 if (!text) {
1155 write("Abbruch! Artikel landet im Reisswolf.\n");
1156 return 1;
1157 }
1158 if (!sizeof(old_explode(text,"\n")-
1159 ({"q","quit"," **","** ","ende","","exit"," "})
1160 ) )
1161 return write("\
1162ACHTUNG: Wolltest Du wirklich einen Artikel ohne Inhalt in die mpa setzen?\n\
1163Artikel ohne erkennbaren Inhalt werden NICHT veroeffentlicht. Bitte ueber-\n\
1164pruef Deine Syntax, falls Du keinen Artikel schreiben wolltest, oder schreib\n\
1165auch ein bisschen Text!\n\
1166Artikel landet im Reisswolf.\n"),1;
1167 if (!message[M_MESSAGE])
1168 message[M_MESSAGE] = text;
1169 else
1170 message[M_MESSAGE]+=text;
1171 if (sig=read_file("/players/"+geteuid(this_interactive())+"/.signature"))
1172 message[M_MESSAGE]+=sig;
1173 if (!CatchNewsError(NEWSSERVER->WriteNote(message),
1174 "Diese Rubrik ist voll. Mist, da war jemand schneller...")) {
1175 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");
1176 return 0;
1177 }
1178 write("OK, Artikel ist veroeffentlicht.\n");
1179 say(capitalize(TP->name())+
1180 " hat einen Artikel in der Zeitung veroeffentlicht.\n");
1181 if (geteuid(TP)!="sitopanaki")
1182 InformPlayers(message[M_BOARD],geteuid(this_interactive()),
1183 "* MPA: Neuer Artikel von "+
1184 capitalize(geteuid(this_interactive()))+
1185 " in Rubrik \""+message[M_BOARD]+"\".\n");
1186 message=0; /* Platz sparen! */
1187 return 1;
1188}
1189
1190
1191//static // allowing aliasing *Rumata* 5/8/96
1192inhalt(str) {
1193 int i,endflag,timeout;
1194 string *gruppen,s,txt,suche;
1195 mixed messages;
1196
1197 if (str=="?"||str=="-?") return
1198 write("Syntax: inhalt [<rubrik>] [ende] [suche <text>]\n"),1;
1199
1200 str=(!str)?({}):explode(str," ");
1201
1202 if (sizeof(str) && (str[0]=="neu" || str[0]=="neues") )
1203 return ReadNextUnread("liste"),1;
1204
1205 if (endflag=member(str,"ende")+1) str-=({"ende"});
1206 if (((i=member(str,"suche")) != -1) && (sizeof(str) > i)) {
1207 suche=lower_case(implode(str[i+1..]," "));
1208 str=str[0..i-1];
1209 }
1210 else
1211 suche=0;
1212 if (!sizeof(str)) {
1213 str=GROUP;
1214 if (!pointerp(messages=NEWSSERVER->GetNotes(str))){
1215 str=GROUP=DEFAULTGROUP;
1216 if (!pointerp(messages=NEWSSERVER->GetNotes(str)))
1217 return notify_fail("Seltsam, irgendwie geht hier einiges schief...\n"),0;
1218 }
1219 }
1220 else {
1221 str=GetGroupName(str[0]);
1222 if (!str) return 1;
1223 messages=NEWSSERVER->GetNotes(str);
1224 }
1225 timeout=abs(read_until[str]);
1226 s="Inhalt der Rubrik "+str+":\n\n";
1227 if (!pointerp(messages) || !sizeof(messages))
1228 return
1229 write(s+"Zur Zeit befinden sich keine Artikel in dieser Rubrik.\n"),1;
1230 if (suche)
1231 s+="Suche nach '"+suche+"' in der Rubrik ergab folgende Treffer:\n\n";
1232 else
1233 if (sizeof(messages)==1)
1234 s+="Zur Zeit befindet sich ein Artikel in der Rubrik:\n\n";
1235 else
1236 s+="Zur Zeit befinden sich "+sizeof(messages)+
1237 " Artikel in der Rubrik:\n\n";
1238 if (endflag&&(sizeof(messages)>16)&&
1239 messages[sizeof(messages)-16][M_TIME]>=timeout) timeout=-1;
1240 for (i=(endflag?(((endflag=sizeof(messages)-15)<0)?0:endflag):0);
1241 i<sizeof(messages);i++)
1242 {
1243 txt=sprintf("%2d.%s%-48s%4d (%-11s) %s\n",i+1,
1244 (((timeout>=0) && timeout<messages[i][M_TIME] )?
1245 ( (timeout=-1),"*"):" "),messages[i][M_TITLE],
1246 sizeof(explode(messages[i][M_MESSAGE],"\n")),
1247 messages[i][M_WRITER],
1248 dtime(messages[i][M_TIME])[5..11]);
1249 if (!suche || (strstr(lower_case(txt), suche) != -1))
1250 s+=txt;
1251 }
1252 if (endflag) write(s);
1253 else this_player()->More(s);
1254 return 1;
1255}
1256
1257
1258static artikel(str) {
1259 return lies(str);
1260}
1261
1262
Zesstra@Morgengrauen795a0e12016-07-19 00:17:42 +02001263static int loesche(string str) {
MG Mud User88f12472016-06-24 23:31:02 +02001264 int num;
1265 mixed *messages;
1266
1267 if (str=="?"||str=="-?") return
1268 write("Syntax: loesche artikel <nr>\n"
1269 " (bezieht sich immer auf die aktuelle Rubrik.\n"),1;
1270
1271 if (!str || sscanf(str,"artikel %d",num)!=1 || num<=0)
1272 return notify_fail("WELCHEN Artikel willst Du loeschen ?\n"),0;
1273 num--;
1274 messages=(NEWSSERVER->GetNotes(GROUP));
1275 if (sizeof(messages)<=num) return
1276 notify_fail("So viele Artikel sind da nicht!\n"),0;
1277
1278 write("Rubrik "+GROUP+", Artikel "+(num+1)+
1279 " von "+capitalize(messages[num][M_WRITER])+
1280 " vom "+dtime(messages[num][M_TIME])[5..26]+
1281 ",\nTitel: "+messages[num][M_TITLE]+",\n\n");
1282
1283 /* (ueberfluessige Abfrage, macht schon /secure/news)
1284 if (!IS_LEARNER(TI) && lower_case(messages[num][M_WRITER])!=geteuid(TI))
1285 return
1286 write("Nicht geloescht - du darfst nur eigene Artikel loeschen.\n"),1;
1287 */
1288
1289 switch (NEWSSERVER->RemoveNote(GROUP, num)){
1290 case 1: write("Artikel ist geloescht.\n");
1291 say(this_player()->name()+" loescht einen Artikel aus der Zeitung.\n");
1292 return 1;
1293 case -1: write("Diesen Artikel darfst Du nicht loeschen.\n");
1294 say(this_player()->name()+" versucht vergeblich, einen Artikel zu loeschen.\n");
1295 return 1;
1296 case -3: write("So viele Artikel sind da nicht !\n");
1297 return 1;
1298 default: write("Interner Fehler. Bitte Erzmagier verstaendigen !\n");
1299 return 1;
Zesstra@Morgengrauen4090ca62016-07-19 00:22:34 +02001300 }
1301 return 0;
MG Mud User88f12472016-06-24 23:31:02 +02001302}
1303
1304// Low-level Funktion zum Abonnieren/Abbestellen von Rubriken
1305// bestellen==0 -> abbestellen, bestellen!=0 -> bestellen
1306// Rueckgabe: 0, wenn der gewuenschte Zustand schon eingestellt war, sonst 1
1307private int _subscribe(string groupname, int bestellen) {
1308
1309 int timeout = read_until[groupname];
1310 // gar nicht abonniert/abbestellt?
1311 if (!bestellen && timeout < 0)
1312 return 0;
1313 else if (bestellen && timeout > 0)
1314 return 0;
1315
1316 // wenn noch kein timeout, erstmal auf 1 setzen
1317 timeout ||= 1;
1318
1319 // -1 fuer abbestellen, +1 fuer bestellen
1320 if (bestellen)
1321 read_until[groupname] = abs(timeout);
1322 else
1323 read_until[groupname] = -timeout;
1324
1325 if (environment())
1326 environment()->SetProp(P_READ_NEWS, read_until);
1327
1328 return 1;
1329}
1330
1331static Unsubscribe(str) {
1332 int timeout;
1333 if (str=="?"||str=="-?") return
1334 write("Syntax: unsubscribe <rubrik>"
1335 " oder: bestelle <rubrik> ab\n"),1;
1336 str=GetGroupName(str);
1337 if (!str) return 1;
1338 if (!_subscribe(str,0)) {
1339 notify_fail("Die Rubrik hast Du gar nicht abonniert!\n");
1340 return 0;
1341 }
1342 else {
1343 write("Rubrik "+str+" abbestellt.\n");
1344 }
1345 return 1;
1346}
1347
1348
1349static Bestelle(str) { /* ab ! */
1350 if (!str || !sscanf(str,"%s ab",str)) return _notify_fail(
1351 "Die Syntax ist: 'bestelle <rubrik> ab', "
1352 "oder meinst Du 'abonniere'?\n"),0;
1353 return Unsubscribe(str);
1354}
1355
1356static Subscribe(str) {
1357 int timeout;
1358 if (str=="?"||str=="-?") return
1359 write("Syntax: abonniere <rubrik>\n"
1360 " oder: subscribe <rubrik>\n"),1;
1361 str=GetGroupName(str);
1362 if (!str) return 1;
1363 if (!_subscribe(str,1)) {
1364 notify_fail("Die Rubrik hast Du doch schon abonniert!\n");
1365 return 0;
1366 }
1367 else {
1368 write("Rubrik "+str+" abonniert.\n");
1369 }
1370 return 1;
1371}
1372
1373// Legt die anfaenglichen Abonnements eines Neulesers fest und bestellt alle
1374// anderen ab.
1375private void InitialSubscriptions() {
1376 // alle abbestellen. ;-)
1377 // Alternative: fuer alle _subscribe(,0) rufen
1378 if (!query_once_interactive(environment()))
1379 return;
1380 string *gruppen = NEWSSERVER->GetGroups();
1381 int *vals = allocate(sizeof(gruppen),-1);
1382 read_until = mkmapping(gruppen,vals);
1383
1384 // jetzt die vorausgewaehlten bestellen
1385 foreach(string gruppe : INITIAL_SUBSCRIPTIONS) {
1386 if (member(gruppen, gruppe) > -1)
1387 _subscribe(gruppe,1);
1388 }
1389 // und ggf. noch die eigene Gildenrubrik
1390 string gilde = environment()->QueryProp(P_GUILD);
1391 if (stringp(gilde)
1392 && member(gruppen, "gilden."+gilde) > -1)
1393 _subscribe("gilden."+gilde,1);
1394
1395 environment()->SetProp(P_READ_NEWS, read_until);
1396}
1397
1398static MoveMessage(str) {
1399 int num,i;
1400 mixed msg/*,expl*/;
1401 string gr;
1402 if (str=="?"||str=="-?") return
1403 write("Syntax: verlege artikel <nr> nach <rubrik>\n"
1404 " Artikel und Rubrik muessen explizit angegeben werden.\n"),1;
1405 if (!str || sscanf(str,"artikel %d nach %s",num,gr)!=2) return (int)notify_fail(
1406 "verlege artikel <nr> nach <rubrik>, oder was?\n");
1407 if (!(gr=GetGroupName(gr))) return 1;
Zesstra@Morgengrauen0e0ac492016-07-19 00:13:51 +02001408 if (gr == GROUP)
1409 {
1410 write("Das waere reichlich sinnlos, nicht wahr?\n");
1411 return 1;
1412 }
MG Mud User88f12472016-06-24 23:31:02 +02001413 if (!(CatchNewsError(NEWSSERVER->AskAllowedWrite(gr),"Die Rubrik ist leider voll.\n"))) return 1;
1414
1415 if (!pointerp(msg=NEWSSERVER->GetNotes(GROUP)))
1416 return notify_fail("Seltsam, die Rubrik '"+GROUP+
1417 "' gibt es nicht mehr...\n"), 0;
1418
1419 num--;
1420 if (sizeof(msg)<=num) return
1421 notify_fail("So viele Nachrichten sind da nicht !\n"),0;
1422 msg=msg[num];
1423 if (geteuid(TI) != lower_case(msg[M_WRITER])) {
1424 if (!IS_LEARNER(TI)) return
1425 write("Du darfst nur Deine eigenen Artikel verlegen.\n"),1;
1426 write("WARNUNG: Das ist nicht Dein eigener Artikel!\n");
1427 }
1428 // return (int)notify_fail("Man darf zur Zeit nur eigene Artikel verlegen.\n");
1429 if (!CatchNewsError(NEWSSERVER->RemoveNote(GROUP,num),"Dieser Fehler kann eigentlich nicht auftreten"))
1430 write("Warnung! Konnte Artikel an alter Position nicht loeschen.\n");
1431 else write("Artikel von Rubrik "+GROUP+" entfernt.\n");
1432
1433 msg[M_MESSAGE]=
1434 sprintf("%s on=%s ot=%d og=%s\n",
1435 STATUSESCAPE,msg[M_WRITER],msg[M_TIME],msg[M_BOARD])
1436 +msg[M_MESSAGE];
1437
1438/*
1439 expl=explode(msg[M_MESSAGE],"\n");
1440 for (i=0;(IS_STATUSLINE(expl[i][0..2]));i++);
1441 msg[M_MESSAGE]=( (i) ? implode(expl[0..i-1],"\n")+"\n" : "" ) +
1442 "[Verlegt von "+msg[M_BOARD]+", "+msg[M_WRITER]+", "+
1443 dtime(msg[M_TIME])[5..26]+"]:\n"+
1444 implode(expl[i..],"\n")+"\n";
1445*/
1446
1447 msg[M_BOARD]=gr;
1448 NEWSSERVER->WriteNote(msg);
1449 write("Artikel nach Rubrik "+gr+" verlegt.\n");
1450 return 1;
1451}
1452
1453static MoveTrash()
1454{
1455 if (!pointerp(lasttitle)||sizeof(lasttitle)<LAST_SIZEOF) return
1456 write("Was denn bitte? Du hast noch gar nichts gelesen!\n"),1;
1457 if (lasttitle[LAST_GROUP]!=GROUP) return
1458 write("Nix gibts! Du hast die Rubrik gewechselt!\n"),1;
1459 return MoveMessage(sprintf("artikel %d nach muell",lasttitle[LAST_NR]+1));
1460}
1461
1462static SaveMessage(str) {
1463 mixed num;
1464 mixed *messages;
1465
1466 if (intp(str)) num=str;
1467 if ((!num && (!str || str=="" || sscanf(str,"artikel %d",num)!=1)) || num<=0) {
1468 notify_fail("Welchen Artikel willst Du abspeichern?\n");
1469 return 0;
1470 }
1471 if (!pointerp(messages=NEWSSERVER->GetNotes(GROUP)))
1472 return notify_fail("Seltsam, die Rubrik '"+GROUP+
1473 "' gibt es nicht mehr...\n"), 0;
1474 num--;
1475 if (sizeof(messages)<=num) {
1476 notify_fail("So viele Nachrichten sind da nicht !\n");
1477 return 0;
1478 }
1479 if(write_file(SAVEMSGPATH(TP),Message2string(num,messages,M2S_REMOTE)+"\n"))
1480 write(break_string(
1481 "Inhalt des Artikels wurde nach "+SAVEMSGPATH(TP)+" gespeichert.\n"));
1482 else
1483 write(break_string(
1484 "Fehler beim Schreiben nach "+SAVEMSGPATH(TP)+"!\n"));
1485 return 1;
1486}
1487
1488
1489static MailMessage(str) {
1490 mixed num,rec,group;
1491 mixed *messages;
1492
1493// printf("%O\n",inherit_list(environment(TP)));
1494// if (member(query_actions(this_player()),"mail")<0)
1495// tut nicht wegen anderer Implemtierung von AddCmd in Raeumen
1496
1497 if (str=="?"||str=="-?") return
1498 write("Syntax: versende artikel <nr> an <adresse>\n"),1;
1499
1500 str=TP->_unparsed_args(); // wegen Mailadressen
1501 if (str) str=lower_case(str);
1502
1503 if (!IS_SEER(TP) && !IS_POST(environment(TP)))
1504 return notify_fail("Du musst in ein Postamt gehen, "
1505 "um etwas versenden zu koennen.\n"),0;
1506
1507 num=0;
1508
1509 if (!str || (sscanf(str,"artikel %d an %s",num,rec)!=2 &&
1510 sscanf(str,"note %d to %s",num,rec)!=2 &&
1511 sscanf(str,"note to %s",rec)!=1 &&
1512 sscanf(str,"artikel an %s",rec)!=1)){
1513 if (!str || str[0..6]=="artikel"||str[0..3]=="note") return
1514 write("Welchen Artikel willst Du versenden, und wohin?\n"),1;
1515 else return
1516 notify_fail("Welchen Artikel willst Du versenden, und wohin?\n"),0;
1517 }
1518 if (!num&&(!pointerp(lasttitle)||sizeof(lasttitle)<LAST_SIZEOF))
1519 return write("Du hast scheinbar noch nichts gelesen, worauf man sich "
1520 "beziehen kann.\nGib notfalls die Nummer des Artikels an.\n"),1;
1521
1522 // printf("lasttitle= %O\nnum=%d\n",lasttitle,num);
1523
1524 if (!pointerp(messages=
1525 NEWSSERVER->GetNotes(group=(num?GROUP:lasttitle[LAST_GROUP]))))
1526 return notify_fail("Seltsam, die Rubrik gibt es nicht mehr...\n"), 0;
1527
1528 if (!pointerp(messages)||!sizeof(messages))
1529 return write("Die Rubrik "+group+" ist leer.\n"),1;
1530 if (num<0||sizeof(messages)<num) return
1531 write("Einen Artikel mit Nummer "+num+" gibt es in Rubrik "+group+
1532 " nicht!\n"),1;
1533
1534 if (num) num--;
1535 else {
1536 int h;
1537 num=-1;
1538 if (pointerp(messages)) {
1539 for (h=sizeof(messages)-1;
1540 (h>=0 && messages[h][M_TIME]>=lasttitle[LAST_TIME]);h--)
1541 if (messages[h][M_TIME]==lasttitle[LAST_TIME] &&
1542 lower_case(messages[h][M_WRITER])==
1543 lower_case(lasttitle[LAST_WRITER]))
1544 num=h;
1545 }
1546 if (num<0)
1547 return notify_fail("Konnte Artikel nicht wiederfinden, "
1548 "bitte gib die Nummer an.\n"),0;
1549 }
1550 MAILER->do_mail( rec,
1551 "MPA: "+messages[num][M_TITLE]+" ("+messages[num][M_WRITER]+")",
1552 Message2string(num,messages,M2S_REMOTE,group)+"\n");
1553 return 1;
1554}
1555
1556
1557
1558HelpPage(str) {
1559 if (str!="mpa"&&str!="zeitung") return 0;
1560 this_player()->More(read_file(HELPPAGE)+
1561 (IS_LEARNER(TP) ? read_file(WIZHELPPAGE) : ""));
1562 return 1;
1563}
1564
1565/*--------------------------------------------------------------------------*/
1566
1567protected void NotifyMove(object dest, object oldenv, int method) {
1568 ::NotifyMove(dest, oldenv, method);
1569
1570 // P_READ_NEWS aus dem Spieler holen.
1571 if (objectp(environment()) && query_once_interactive(environment())) {
1572 read_until=environment()->QueryProp(P_READ_NEWS);
1573 }
1574
1575 if (!mappingp(read_until) || !sizeof(read_until))
1576 InitialSubscriptions();
1577}
1578
1579int GetTID(mixed message) {
1580 string dummy;
1581 int tid;
1582 return (sscanf(message[M_MESSAGE],"%s" STATUSESCAPE " tid=%d",dummy,tid)==2)
1583 ? tid : message[M_TIME];
1584}
1585