blob: b78d0b6e398aab036d003a7e616578aeafcef793 [file] [log] [blame]
Zesstra25387d92017-02-03 20:20:56 +01001/* =========================================================================
2
Arathorn4c2c85d2020-03-09 23:12:26 +01003 Ein Mailobjekt fuer Morgengrauen.
Zesstra25387d92017-02-03 20:20:56 +01004 (C) 1993-97 Loco@MG. Unter Verwendung des std/post-codes von Jof
Arathorn4c2c85d2020-03-09 23:12:26 +01005
Zesstra25387d92017-02-03 20:20:56 +01006 Verwendung ausserhalb von Morgengrauen ist gestattet unter folgenden
7 Bedingungen:
8 - Benutzung erfolgt auf eigene Gefahr. Jegliche Verantwortung wird
9 abgelehnt.
10 - Auch in veraenderten oder abgeleiteten Objekten muss ein Hinweis auf
11 die Herkunft erhalten bleiben.
12 - Bitte Loco Bescheid sagen.
13 Ein Update-Service besteht nicht. Diese Lizenz kann jederzeit
14 zurueckgezogen werden.
15
16 Letzte Aenderungen:
17 190494 [Loco] mail <spieler> fuehrt nicht ins mailmenue anschliessend.
18 280494 [Loco] .mailrc
19 020594 [Loco] system.mailrc, aliase anzeigen, Text retten, selfdestruct
20 in reset() im Fehlerfall, kleinere bugfixes
21 070794 [Loco] Kleinigkeiten (bugfixes und Optimierungen), '+'
22 231195 [Loco] Bereiche bei Speichern und Loeschen
23 171295 [Loco] Bereiche bei forward. Stapelweise Kleinigkeiten.
24 191295 [Loco] Kleinere Zeitoptimierungen, teilweise schiefgelaufen und
25 deswegen doch nicht, minor bugfixes.
26 190295 [Loco] keine folderlist beim hochstarten
27 110696 [Loco] Forwardserver-Unterstuetzung (.forward-aehnlich)
28 031296 [Loco] major update:
29 Erlaube in der Blueprint nichtinteraktives Versenden
30 vorbereiteter mails (z.B. fuer mpa: versende artikel);
31 Zeitoptimierungen durch effektiveres caching;
32 '-';
33 Einige optische Aenderungen;
34 Warnung bei grossen mailfiles;
35 Unterstuetzung von bcc's;
36 d,m,f,s erlauben Listen;
37 Abkuerzungen und '-' bei Folderargumenten
38 080297 [Loco] Zeitoptimierungen, interne Aenderungen, Bugfixes
39 280103 [Muadib]Silentflag
40 020304 [Vanion]In do_mail() wird jetzt M_NOCHECK gemovet, sonst hat ein
41 Mailer eines Spielers, der voll ist, kein Environment.
42 100105 [Zook] Magier mit Level >= 26 bekommen erst spaeter eine
Arathorn4c2c85d2020-03-09 23:12:26 +010043 Mitteilung (Gebietswartung insb. f. Regionsmagier
44 erfordert schlicht ein groesseres Postfach).
45
Zesstra25387d92017-02-03 20:20:56 +010046----------------------------------------------------------------------------
47
48Aufrufe von aussen zur Benutzung:
49
Arathorn4c2c85d2020-03-09 23:12:26 +010050a) im geklonten Objekt:
Zesstra25387d92017-02-03 20:20:56 +010051 obj->do_mail() interaktives Mailmenue
52 obj->do_mail(empf) 'halbinteraktiv': _eine_ mail, an Empfaenger str
53 Objekt zerstoert sich nach Gebrauch selbst.
Arathorn4c2c85d2020-03-09 23:12:26 +010054 Bei obj->do_mail("-silent") wird der Inhalt des Mailfolders nicht
Zesstra25387d92017-02-03 20:20:56 +010055 aufgelistet. Ansonsten wie obj->do_mail()
Arathorn4c2c85d2020-03-09 23:12:26 +010056
Zesstra25387d92017-02-03 20:20:56 +010057b) in der blueprint: nur non-interactive
58 obj->do_mail(empf,titel,text)
Arathorn4c2c85d2020-03-09 23:12:26 +010059 sendet mail mit Titel titel und Inhalt text an Empfaenger empf.
Zesstra25387d92017-02-03 20:20:56 +010060 Aliase etc. werden von this_interactive() genommen.
61 Nur fuer 'trusted objects' zugelassen, siehe #define TRUSTED
62
63=========================================================================== */
64
65#include "post.h"
66
Zesstraafd72e02017-02-03 20:32:56 +010067inherit "/std/thing";
Zesstra25387d92017-02-03 20:20:56 +010068//inherit "std/more"; // wird vom nedit inherited
69inherit NEDIT;
70
71#include <properties.h>
72#include <language.h>
73#include <config.h>
74#include <mail.h>
75#include <wizlevels.h>
76#include <moving.h>
77#include <defines.h>
78#include <input_to.h>
79
80#undef DEBUG
81
82#define TRUSTED(o) (objectp(o) && BLUE_NAME(o)=="/obj/mpa")
83// (geteuid(o)=="p:service"|| \
84// geteuid(o)==geteuid(this_interactive())))
85
Zesstraafd72e02017-02-03 20:32:56 +010086#define MAILFILE(name) (MAILPATH+name[0..0]+"/"+name)
Zesstra25387d92017-02-03 20:20:56 +010087#define MAILFILEO(name) (MAILFILE(name)+".o")
88#define MAILDEMON0297 // Maildemon-Version 8.Feb.97 vorhanden?
89
90#define IS_NUMBER(n) (stringp(n) && sizeof(n) && n[0]>='0' && n[0]<='9')
91
92#ifdef DEBUG
93#define DEBUGVAR(x) if(find_player("tiamak")) tell_object(find_player("tiamak"),sprintf("Value of x is %O\n",x))
94#else
95#define DEBUGVAR(x)
96#endif
97
98// Zaehlung: akt_nr ab 1, akt_folder ab 0
99
100static string subject, message, receiver, sender, *carbon;
101#ifdef MAIL_SUPPORT_BCC
102static string* blindcarbon;
103#endif
104static string name, office_name;
105static int done, akt_folder, i, akt_nr, directflag;
106static int folder_size,folder_date; // cacheverwaltung
107static mapping aliases;
108
109mixed *folders;
110
111// Prototypen, die nun mal gebraucht werden
112
113static varargs void SendMail(string text,int flag);
114static void input();
115static mixed process_names(mixed s);
116static void get_carbon_copy(string str);
117static varargs string* send_mail(mixed back);
118string * unify_array(string * a);
119static mapping Read_mailrc(string file);
120static varargs void update(int directflag,int nocondflag);
Arathorn4c2c85d2020-03-09 23:12:26 +0100121static varargs void ListContent(int limit);
Zesstra25387d92017-02-03 20:20:56 +0100122string GetFolderName(mixed fol);
123static void LagWarning();
124string GetReTitle(string s);
125static string Message2string(int nr);
126int * GetNumbers(mixed s);
127
Zesstra93769582019-11-29 00:32:59 +0100128protected void create() {
129 ::create();
Zesstra25387d92017-02-03 20:20:56 +0100130 seteuid(getuid());
131 SetProp(P_IDS,({"mailer"}));
132 SetProp(P_NAME,"mailer");
133 office_name="Morgengrauens Post";
134 akt_folder=-1;
135 folder_size=folder_date=-42;
136 SetProp(P_NODROP,1);
137 SetProp(P_SHORT,0);
138 SetProp(P_WEIGHT,0);
Arathorn4c2c85d2020-03-09 23:12:26 +0100139}
Zesstra25387d92017-02-03 20:20:56 +0100140
141
Zesstra93769582019-11-29 00:32:59 +0100142public varargs void init(object origin) {
Zesstra25387d92017-02-03 20:20:56 +0100143 (::init());
144 init_rescue();
145 add_action("postneustart","post");
146 add_action("postneustart","mail");
147}
148
149
150void reset() {
151 object pl;
152 (::reset());
153 if (!name) {remove();return;}
154 pl=find_player(name);
155 if (!pl || environment()!=pl) {remove();return;}
156 if (nedittext && !query_input_pending(pl)) {
157 tell_object(pl,"\
158*** Hoppla! Du hast noch einen nicht fertiggeschriebenen Brief!\n\
159*** Mit ~r kannst Du weiterschreiben.\n");
160 return;
161 }
162 if (query_input_pending(pl)!=this_object())
163 {remove();return;}
164}
165
166
167mixed postneustart() {
168 if (!this_interactive() || name!=geteuid(this_interactive())
169 || query_input_pending(this_interactive())
170 || this_interactive()!=this_player()) return 0;
171 write("Und weiter gehts...\n");
172 if (nedittext) return RescueText();
173 return input();
174}
175
176
177string SetOfficeName(string n) {
178 return office_name=n;
179}
180
181
182static varargs void write_mail(mixed str, string std_subject, string text) {
183 string str2;
Arathorn4c2c85d2020-03-09 23:12:26 +0100184
Zesstra25387d92017-02-03 20:20:56 +0100185 carbon=process_names(str);
Arathorn4c2c85d2020-03-09 23:12:26 +0100186 if (!sizeof(carbon)) {
Zesstra25387d92017-02-03 20:20:56 +0100187 write("Kein Empfaenger angegeben!\n"),(directflag?remove():input());
188 return;
189 }
190 write("Empfaenger: "+implode(map(carbon,#'capitalize/*'*/),", ")+"\n");
191 str=carbon[0];
192 if (sizeof(carbon)>=2) carbon=carbon[1..<1];
193 else carbon=0;
194 if ((str2=str) && str2!="" && str2[0]=='\\') str2=str2[1..];
195 if (!str) { write("WEM willst Du schreiben?\n"),(directflag?remove():input()); return;
196 }
197 if (!master()->find_userinfo(str2) && member(str2,'@')==-1)
198 {
199 write("Mit dem Namen gibt es hier niemanden.\n"),(directflag?remove():input());
200 return;
201 }
Arathorn4c2c85d2020-03-09 23:12:26 +0100202
Zesstra25387d92017-02-03 20:20:56 +0100203 receiver=str;
204
205 if (text) {
206 subject=std_subject;
207 return SendMail(text,1); // flag 1: keine CC's bitte.
208 }
209
210 //write("Titel");
211 //if (std_subject) write(" ("+std_subject+")");
212 //write(": ");
213 string pr;
214 if (std_subject) pr = "Titel ("+std_subject+"): ";
215 else pr = "Titel: ";
216 subject=std_subject;
217 input_to("get_subject",INPUT_PROMPT,pr);
218 return;
219}
220
221
222static varargs void get_subject(string str,string pretext) {
223 DEBUGVAR(str);
224 DEBUGVAR(subject);
225 if ((!str||str=="") && !subject)
226 {
227 input_to("get_subject",INPUT_PROMPT,"Titel (Abbrechen mit ~q): ");
228 return;
229 }
230 if (str=="~q"||str=="~Q") return SendMail(0); // entspricht Abbruch im Editor.
231 if (str && str!="") subject=str;
232 write("Bitte gib jetzt Deine Nachricht an:\n\
233** oder . wenn fertig, ~q fuer Abbruch, ~h fuer eine Hilfsseite\n");
234 nedit("SendMail",pretext);
235}
236
237
238static varargs void SendMail(string text,int flag) {
239 // flag: 1 = keine CC abfragen.
240 if (!text) {
241 write("Abbruch! Brief landet im Reisswolf.\n");
242 if (directflag) {remove(); return;
243 }
Arathorn4c2c85d2020-03-09 23:12:26 +0100244
Zesstra25387d92017-02-03 20:20:56 +0100245 subject=receiver=carbon=message=0;
246 return input();
247 }
248 message=text;
249 if (flag) return get_carbon_copy(0);
250 //write("Cc: ");
251 input_to("get_carbon_copy",INPUT_PROMPT, "Cc: ");
252 return;
253}
254
255
256static void get_carbon_copy(string str) { // Aufruf mit 0, wenn keine cc gewuenscht.
257 int i,j;
258 object p;
259 string *oldcarbons,*h,*receivers;
260 mapping orignames;
Arathorn4c2c85d2020-03-09 23:12:26 +0100261
Zesstra25387d92017-02-03 20:20:56 +0100262 oldcarbons=carbon;
263 if (str=="~q") return SendMail(0); // Abbruch, entspricht Abbruch im Editor
264 if (!str || str=="") carbon=0;
265 else carbon=process_names(str);
266 carbon=(oldcarbons ? oldcarbons : ({}))+(carbon ? carbon : ({}));
267
268#ifdef MAIL_SUPPORT_BCC
269 blindcarbon=filter(carbon,
270 function status (string x)
271 {if (x[0]=='-') return(1);
272 return(0);});
273 carbon-=blindcarbon;
274 blindcarbon=map(blindcarbon,
Arathorn4c2c85d2020-03-09 23:12:26 +0100275 function string (string x)
Zesstra25387d92017-02-03 20:20:56 +0100276 {return(x[1..]);} );
277#endif
278
279#ifdef MAIL_SUPPORT_BCC
280 oldcarbons=({receiver})+carbon+blindcarbon; // speichere alle Originaladressen
281#else
282 oldcarbons=({receiver})+carbon;
283#endif
284
285 /* Forwards auswerten, dabei werden auch ungueltige Adressen gefiltert */
286 /* orignames speichert die Zuordnung Zieladressen -> Originaladressen */
287
288 orignames=([]);
289 h=explode(FWSERV->QueryForward(receiver),",");
290
291 DEBUGVAR(h);
292 for (j=sizeof(h);j--;)
293 orignames[(h[j][0]=='\\'?h[j][1..]:h[j])]=({receiver[0]=='\\'?receiver[1..]:receiver});
294 receiver=h[0];
295 receivers=h[1..]; // Missbrauch dieser Variable!
296
297 DEBUGVAR(orignames);
298
299 for (i=sizeof(carbon);i--;) {
300 h=explode(FWSERV->QueryForward(carbon[i])||"",",");
301 for (j=sizeof(h);j--;) {
302 h[j]=(h[j][0]=='\\'?h[j][1..]:h[j]);
303 orignames[h[j]]=(orignames[h[j]]||({}))+({carbon[i][0]=='\\'?carbon[i][1..]:carbon[i]});
304 receivers+=h;
305 }
306 }
307 carbon=receivers;
308
309#ifdef MAIL_SUPPORT_BCC
310 receivers=({});
311 for (i=sizeof(blindcarbon)-1;i>=0;i--) {
312 h=old_explode(FWSERV->QueryForward(blindcarbon[i]),",");
313 for (j=sizeof(h)-1;j>=0;j--) {
314 h[j]=(h[j][0]=='\\'?h[j][1..]:h[j]);
315 orignames[h[j]]=(orignames[h[j]]||({}))+({blindcarbon[i][0]=='\\'?blindcarbon[i][1..]:blindcarbon[i]});
316 receivers+=h;
317 }
318 }
319 blindcarbon=receivers;
320#endif
321
322 carbon=send_mail();
323 receivers=({});
324
325 if (!pointerp(carbon) || !sizeof(carbon)){
326 write("Brief NICHT verschickt, da keine Empfaenger gefunden!\n");
Arathorn4c2c85d2020-03-09 23:12:26 +0100327 } else {
328 string *a;
Zesstra25387d92017-02-03 20:20:56 +0100329 DEBUGVAR(orignames);
330 for (i=0;i<sizeof(carbon);i++){
331 DEBUGVAR(carbon[i]);
332 /* evtl. abfragen nach query_editing und/oder query_input_to */
333 /* Benachrichtige Spieler, die ein forward gesetzt haben */
334 a=orignames[carbon[i]];
335 if (pointerp(a))
336 {
337 a=a-({carbon[i]});
Arathorn4c2c85d2020-03-09 23:12:26 +0100338 for (j=sizeof(a);j--;)
339 if (p=find_player(a[j]))
Zesstra25387d92017-02-03 20:20:56 +0100340 tell_object(p,"Ein Postreiter ruft Dir aus einiger Entfernung zu, dass Du neue Post hast!\nDer Brief wurde wunschgemaess weitergeleitet.\n");
341 }
342 /* Benachrichtige Empfaenger */
343#ifndef MAILDEMON0297
Arathorn4c2c85d2020-03-09 23:12:26 +0100344 if (p=find_player(carbon[i]))
Zesstra25387d92017-02-03 20:20:56 +0100345 tell_object(p,"Ein Postreiter ruft Dir aus einiger Entfernung zu, dass Du neue Post hast!\n");
346#endif
347 receivers+=orignames[carbon[i]]||orignames["\\"+carbon[i]]||({});
348 }
349 DEBUGVAR(carbon);
350 write("Abgesandt an: "+implode(unify_array(map(receivers,#'capitalize)),", ")+"\n");//')));
351 }
352 for (i=sizeof(oldcarbons);i--;)
353 if (oldcarbons[i][0]=='\\')
354 oldcarbons[i]=oldcarbons[i][1..];
355 oldcarbons=oldcarbons-receivers;
356 if (sizeof(oldcarbons)) {
357 write("Empfaenger unbekannt: "+implode(map(oldcarbons,#'capitalize),", ")+"\nIrgendjemand wirft Dir den zurueckgekommenen Brief zu.\n");//')))
358 send_mail(oldcarbons);
359 }
360
361 message=receiver=carbon=subject=0;
362 if (directflag) {
363 if (directflag==1) remove(); // 1: Direktmodus, 2: non-interactive
364 return;
365 }
366 return input();
367}
368
369
370static varargs string* send_mail(mixed back) {
371 mixed *mail;
Arathorn4c2c85d2020-03-09 23:12:26 +0100372
Zesstra25387d92017-02-03 20:20:56 +0100373 mail=allocate(9);
374
375#ifdef DEBUG
376 DEBUGVAR(receiver);
377 DEBUGVAR(carbon);
378#endif
379
380 if (!pointerp(carbon) || !sizeof(carbon)) carbon=0;
381 mail[MSG_FROM]=this_player()->query_real_name();
382 mail[MSG_SENDER]=office_name;
383 mail[MSG_RECIPIENT]=(back ? mail[MSG_FROM] : receiver);
384 mail[MSG_CC]=(back ? 0 : carbon);
385#ifdef MAIL_SUPPORT_BCC
386 mail[MSG_BCC]=blindcarbon;
387#else
388 mail[MSG_BCC]=0;
389#endif
390
391 mail[MSG_SUBJECT]=(back ? "Zurueck! Empfaenger unbekannt: "+implode(back,", ") : subject);
392 mail[MSG_DATE]=ctime(time());
393 mail[MSG_ID]="MorgenGrauen:"+time();
394 mail[MSG_BODY]=message;
395 return MAILDEMON->DeliverMail(mail,NO_SYSTEM_ALIASES|NO_USER_ALIASES);
396}
397
Zesstra25387d92017-02-03 20:20:56 +0100398varargs void do_mail(mixed str,string titel,string text) {
399 // text und titel angegeben: versende Text, keine weiteren Taetigkeiten.
400
Arathorn4c2c85d2020-03-09 23:12:26 +0100401 int i;
Zesstra25387d92017-02-03 20:20:56 +0100402 int silent;
Arathorn4c2c85d2020-03-09 23:12:26 +0100403
404 if (name)
405 return; /* security flag :-) */
406
407 if (!this_interactive())
408 return;
409
Zesstra25387d92017-02-03 20:20:56 +0100410 if (!text) {
Arathorn4c2c85d2020-03-09 23:12:26 +0100411 name = geteuid(this_interactive());
412 move(this_interactive(), M_NOCHECK);
413 if (!name)
414 remove();
Zesstra25387d92017-02-03 20:20:56 +0100415 }
Arathorn4c2c85d2020-03-09 23:12:26 +0100416
417 aliases = Read_mailrc(ALIASFILE(geteuid(this_interactive())))+
418 Read_mailrc(SYSALIAS);
419
420 int display_limit;
421 if (str)
422 {
423 str = lower_case(str);
424
425 // Eingabestring zerlegen, um die Elemente der Reihe nach parsen zu
426 // koennen.
427 string* params = explode(str, " ");
428 string* recipients = ({});
429
430 /* Ueber alle Argumente laufen und auf Verwendbares pruefen.
431 Muss for() sein, damit wir zwischendrin mittels p++ Eintraege
432 ueberspringen koennen.
433 Gueltige Argumente sind -show [<zahl>|zeilen], -silent,
434 Empfaengerliste.
435 Wenn hinter -show irgendwas kommt, das weder Integer noch "zeilen"
436 ist, wird es verworfen.
437 Wenn irgendwelche Empfaenger angegeben sind, wird auf jeden Fall
438 an write_mail() weitergegeben, egal was sonst fuer Argumente
439 dabeiwaren. Dies ist Absicht, damit man sich z.B. ein Alias
440 "mail -show 20 $*" bauen kann, das ohne weitere Angaben den
441 Posteingang oeffnet, aber eine neue Mail erstellt, wenn man dahinter
442 einen Empfaenger angibt. Auf diese Weise kann man einen im Alias
443 eingestellten Defaultwert bei der Eingabe des Befehls immer noch
444 mit -silent oder einer anderen Zahl ueberschreiben. */
445 int p;
446 for(p=0; p<sizeof(params); p++)
Zesstra25387d92017-02-03 20:20:56 +0100447 {
Arathorn4c2c85d2020-03-09 23:12:26 +0100448 // Wenn das Argument -silent ist, Flag setzen.
449 if (params[p] == "-silent")
450 {
451 display_limit = 0;
452 silent = 1;
Zesstra25387d92017-02-03 20:20:56 +0100453 }
Arathorn4c2c85d2020-03-09 23:12:26 +0100454 // Wenn es -show ist, checken wir ob das Array noch ein weiteres
455 // Element enthaelt und wenn ja, werten wir es aus und
456 else if (params[p] == "-show")
457 {
458 // hat das Array noch ein Element nach -show?
459 if (sizeof(params) >= p+2)
460 {
461 // wenn ja, ist es ein String ungleich Leerstring?
462 if (sizeof(params[p+1]))
463 {
464 string howmany = params[p+1];
465 // "zeilen" zuerst checken, weil das sonst im naechsten Check
466 // auch zu silent = 1 fuehren wuerde.
467 if (howmany == "zeilen")
468 display_limit = this_player()->QueryProp(P_SCREENSIZE);
469 // Kann man es in ein Integer >0 wandeln?
470 // Wenn 0 rauskommt, wurde entweder "-show 0" angegeben, oder
471 // ein ungueltiger Parameter. Beides interpretieren wir als
472 // "silent".
473 else if (to_int(howmany) == 0)
474 silent = 1;
475 // Alle anderen Ergebnisse werden als Zeilenlimit fuer die
476 // Anzeige interpretiert.
477 else
478 display_limit = to_int(howmany);
479 }
480 // Argumente nach -show werden in jedem Fall nicht nochmal
481 // verarbeitet, d.h. ein Schleifendurchlauf wird uebersprungen.
482 p++;
483 }
484 }
485 // Alles andere duerfte dann wohl ein Adressat sein.
486 else
487 {
488 recipients += ({params[p]});
489 }
490 }
491
492 // Wenn wir potentielle Empfaenger identifiziert haben, bauen wir den
493 // Argumentstring neu zusammen, damit wir ihn spaeter an write_mail()
494 // uebergeben koennen.
495 if(sizeof(recipients))
496 {
497 str = implode(recipients, " ");
498 directflag = 1;
499 if (text)
500 {
501 if (this_interactive()!=this_player())
502 return 0;
503 if (!TRUSTED(previous_object()))
504 return write(break_string(
505 "WARNUNG!!! Objekt "+object_name(previous_object())+" versucht, "
506 "Mail mit Deinem Absender zu versenden! Bitte Erzmagier oder "
507 "Loco verstaendigen.",78)+"\n");
508 directflag = 2;
509 return write_mail(str, titel, text);
510 }
511 directflag = 1;
Zesstra25387d92017-02-03 20:20:56 +0100512 return write_mail(str);
513 }
514 }
Arathorn4c2c85d2020-03-09 23:12:26 +0100515
Zesstra25387d92017-02-03 20:20:56 +0100516 update(0,1);
517 if (!pointerp(folders) || sizeof(folders)!=2 || sizeof(folders[0])==0) {
518 write("Du hast im Moment keine Post !\n");
519 folders=({({}),({})});
520 }
521 write("Du hast "+sizeof(folders[0])+" Ordner, Liste mit 'i'.\n");
522
523 if(!silent)
524 {
Arathorn4c2c85d2020-03-09 23:12:26 +0100525 ListContent(display_limit);
Zesstra25387d92017-02-03 20:20:56 +0100526 }
Arathorn4c2c85d2020-03-09 23:12:26 +0100527
Zesstra25387d92017-02-03 20:20:56 +0100528 write("Gesamtgroesse Deines Postfachs: "+
529 (i=(file_size(MAILFILEO(name))+512)/1024)+" KB.\n");
530 // Kleiner Hack als Uebergangsloesung, weil ich die dumme Warnung
531 // nicht mehr sehen kann. ;^)
532 // 22.10.2000, Tiamak
533 if(IS_ARCH(this_interactive())) i=0;
534
535 //
536 // Kleiner Hack, damit Regionsmitarbeiter und groessere Magier
537 // bei ihren Gebietswartungen nicht staendig mit nervigen
538 // Meldungen belaestigt werden:
539 //
540 // 2005-01-10, Zook
541 if (query_wiz_level(this_interactive()) > DOMAINMEMBER_LVL) {
Arathorn4c2c85d2020-03-09 23:12:26 +0100542 if (i>700)
Zesstra25387d92017-02-03 20:20:56 +0100543 write("*************************************************************\n"
544 "* Dein Postfach ist zu gross! Bitte versuche aufzuraeumen *\n"
545 "* und damit die Groesse zu reduzieren. Grosse Postfaecher *\n"
546 "* verursachen unnoetiges Lag fuer die Spieler. *\n"
547 "*************************************************************\n");
548 i=0;
549 }
550
551 if (i>500) // Extra-Warnung fuer Catweazle
552 // man koennte natuerlich auch eine Channel-Meldung ausspucken
553 // mit dem Hinweis, wer das aktuelle Lag verursacht... vielleicht
554 // ab 800 KB? ;-)
555 write("*****************************************************************\n"
556 "* Dein Postfach hat eine absolut unakzeptable Groesse erreicht. *\n"
557 "* Uebergrosse Postfaecher verursachen unnoetiges Lag fuer alle! *\n"
558 "* Bitte raeume es dringend auf, d.h. loesche alle Briefe, die *\n"
559 "* Du nicht _unbedingt_ benoetigst, oder lager sie aus und *\n"
560 "* loesche sie anschliessend. Hauptsache, weg damit. *\n"
561 "*****************************************************************\n");
562 else if (i>300) // Warnung fuer bestimmte Magier und Seher ab 300 KB
563 write("WARNUNG! Dein Postfach hat eine bedenkliche Groesse erreicht.\n"
564 "Beachte, dass uebergrosse Postfaecher nicht nur unnoetig Speicher, sondern\n"
565 "insbesondere auch Rechenzeit verbrauchen und damit groesseres Lag verursachen\n"
566 "koennen. Du solltest also dringend aufraeumen und alle nicht unbedingt\n"
567 "notwendigen Briefe loeschen (evtl. natuerlich vorher auslagern.\n");
568 else if (i>200) // Hinweis fuer andere.
569 write("Der Postbeamte macht dich darauf aufmerksam, dass Dein Postfach bereits\n"
570 "ziemlich voll ist und Du dringend einmal aufraeumen solltest.\n");
571 else if (i>100) // Hinweis fuer andere.
572 write("Der Postbeamte macht dich darauf aufmerksam, dass Dein Postfach\n"
573 "relativ voll ist.\n");
Arathorn4c2c85d2020-03-09 23:12:26 +0100574
Zesstra25387d92017-02-03 20:20:56 +0100575
576 if ((i=FWSERV->QueryForward(name))!=name)
577 write("Du hast einen Nachsendeauftrag gestellt, Deine Post wird an\n"
578 +i+" weitergeleitet.\n");
579 return input();
580}
581
582
583static void MediumHelpPage() {
Arathorn4c2c85d2020-03-09 23:12:26 +0100584 if (sizeof(folders[0]))
Zesstra25387d92017-02-03 20:20:56 +0100585 write("Aktueller Ordner ist \""+folders[0][akt_folder]+"\"\n");
586 write("\n\
587Brief <nr> lesen '<nr>' (lies <nr>)\n\
588Aktueller / naechster / letzter Brief '.' / '+' / '-'\n\
589Brief schreiben 'm <name>' (schreibe)\n\
590Brief beantworten 'r [nr]' (beantworte)\n\
591Gruppenantwort an alle Empfaenger 'g [nr]' (gruppe)\n\
592Brief(e) loeschen 'd [nummern]' (loesche)\n\
593Brief(e) weitersenden 'f [nummern] <name>' (weiter)\n\
594Weitersenden plus eigenen Text 'F [nr] <name>' (Weiter)\n\
595Brief(e) in anderen Ordner verschieben 'v [nummern] <ordner>' (verschiebe)\n\
596Mails in diesem Ordner listen 'l' (oder nichts) (anzeigen)\n\
597Aktuellen Ordner wechseln 'c <ordner>' (oeffne)\n\
598Neuen Ordner anlegen 'n <ordnername>' (erzeuge)\n\
599Leeren Ordner loeschen 'e <ordner>' (entferne)\n\
600Alle Ordner anzeigen 'i' (ordner)\n\
601"+ (IS_WIZARD(this_player()) ? "\
602Brief(e) speichern in Datei 's [nummern]' (speichere)\n\
603 "+SAVEFILENAME+"\n" : "")+ "\
604Mailaliase anzeigen 'a' (aliase)\n\
605Verfuegbare Kommandos zeigen '?' oder 'h'\n\
606Postmenue verlassen 'q'\n\
607Kommando <cmd> ausfuehren '!<cmd>'\n\
608[nummern] bedeutet: [nr|nr-nr [nr|nr-nr ...]]. (Liste von Nr und Bereichen)\n\
609Bei der Langform reicht es, die ersten 4 Zeichen eines Kommandos anzugeben.\n\
610Falls ein Befehl (z.B. \'v\' nicht funktioniert, pruefe bitte, ob dies ein \n\
611clientseitiges Makro bei Dir ist.\n\
612");
613 return input();
614}
615
616static varargs int GetFolders(int nocondflag) {
617// nocondflag: no condition, unbedingt neuladen
618
619// Cache-Verwaltung endlich funktionsfaehig [251196]
620// IDEE: Uhrzeit & Groesse untersuchen, ausserdem nach Verschieben neuladen.
621// Auch nach automatischem Verschieben (unread -> newmail)!
622
623
624// write("DEBUG: GetFolders called, old date "+folder_date+", old size "+folder_size+", nocondflag="+nocondflag+"\n");
Arathorn4c2c85d2020-03-09 23:12:26 +0100625 if (!nocondflag &&
Zesstra25387d92017-02-03 20:20:56 +0100626 file_time(MAILFILEO(name))==folder_date &&
627 file_size(MAILFILEO(name))==folder_size) return 0;
628
629 if (!restore_object(MAILFILE(name))) folders=({({}),({})});
630 folder_date=file_time(MAILFILEO(name));
631 folder_size=file_size(MAILFILEO(name));
632 if (!pointerp(folders) || sizeof(folders)!=2) folders=({({}),({})});
633// write("DEBUG: GetFolders finished, new date "+folder_date+", new size "+folder_size+"\n");
634 return 1;
635}
636
637static varargs void update(int directflag,int nocondflag) {
638 // directflag: Mailer wird im Direktmodus betrieben
639 // nocondflag: Unbedingt neuladen
640
Arathorn48c2a4a2022-02-07 22:11:08 +0100641 int j,k,newletters;
Zesstra25387d92017-02-03 20:20:56 +0100642 mixed *ignored;
Arathorn4c2c85d2020-03-09 23:12:26 +0100643
Zesstra25387d92017-02-03 20:20:56 +0100644 if (!GetFolders(nocondflag)) return; // es hat sich nix getan
645
646 if (akt_nr<1) akt_nr=1;
647
648 DEBUGVAR(akt_folder);
649
650 if (akt_folder>=sizeof(folders[0]) || akt_folder<0) {
651 akt_folder=member(folders[0], "newmail");
652 if (akt_folder==-1) {
653 MAILDEMON->MakeFolder("newmail",name);
654 GetFolders(1);
655 DEBUGVAR(folders[0]);
656 akt_folder=member(folders[0], "newmail");
657 }
658 if (!directflag && akt_folder!=-1) write("Ordner 'newmail' aufgeschlagen.\n");
659 }
660
661// if (!pointerp(folders)) return write("ERROR: folders no array in update\n"); // Kann eigentlich nicht vorkommen
662 if (sizeof(folders[0]) && akt_nr>sizeof(folders[1][akt_folder]))
663 akt_nr=sizeof(folders[1][akt_folder]);
664 j=member(folders[0], "unread");
665 if (j==-1) return;
666 newletters=0;
667
668 // Testweise eine neue Version, die aber voraussetzt, dass die Position von
669 // unread in der Folderliste von /secure/mail waehrend der Aktion
670 // nicht veraendert wird.
671 // alt ausgeklammert, ausserdem ueberall 0 statt k
672 // k=0;
673 // Neue Version wieder testweise drin
674
675 // while (j != -1 && pointerp(folders[1][j]) && sizeof(folders[1][j])>0) {
676 for (k=0;k<sizeof(folders[1][j]);k++) {
677
678 // write("DEBUG: j="+j+"\n");
Arathorn4c2c85d2020-03-09 23:12:26 +0100679
Zesstra25387d92017-02-03 20:20:56 +0100680 if (pointerp(ignored=this_player()->QueryProp(P_IGNORE)) &&
681 member(ignored, lower_case(folders[1][j][k][MSG_FROM]+".mail"))>=0) {
682 mixed msg;
683 msg=folders[1][j][k];
684 write("Du laesst einen Brief von "+capitalize(msg[MSG_FROM])+
685 " unbesehen zurueckgehen.\n");
686 msg[MSG_BODY]=this_player()->name()+" \
687hat diesen Brief ungeoeffnet an Dich zurueckgehen lassen\n\
688und moechte nicht mehr von Deinen Briefen belaestigt werden.\n\
689Titel: "+msg[MSG_SUBJECT]+"\n\
690------ Inhalt: ------------------------\n"+
691 msg[MSG_BODY];
692 msg[MSG_RECIPIENT]=msg[MSG_FROM];
693 msg[MSG_SUBJECT]="Annahme verweigert - zurueck an Absender";
694 msg[MSG_CC]=0;
695 msg[MSG_BCC]=0;
696 MAILDEMON->DeliverMail(msg,NO_SYSTEM_ALIASES|NO_USER_ALIASES);
697 if (find_player(msg[MSG_RECIPIENT]))
698 tell_object(find_player(msg[MSG_RECIPIENT]),
699 "Ein Postreiter ruft Dir aus einiger Entfernung leicht sauer zu, dass er einen\nzurueckgekommenen Brief fuer Dich hat.\n");
700 MAILDEMON->RemoveMsg(0,j,name);
701 } else {
702 // Testweise durch DeleteUnreadFolder ersetzt (080297)
703#ifndef MAILDEMON0297
704 MAILDEMON->MoveMsg(0, j, "newmail", name);
705#endif
706 newletters++;
707 }
708 // GetFolders(1);
709 // j=member_array("unread",folders[0]);
710 // Letzte 2 Zeilen in "neuer" Version ersatzlos gestrichen
711 }
712
713#ifdef MAILDEMON0297
714 MAILDEMON->DeleteUnreadFolder(name);
715#else
716 MAILDEMON->RemoveFolder("unread",name);
717#endif
718 if (newletters) {
Arathorn4c2c85d2020-03-09 23:12:26 +0100719 if (office_name=="mpa Kurierdienst")
Zesstra25387d92017-02-03 20:20:56 +0100720 write(break_string("Ein Kurier sagt \"Tach, Post!\", drueckt Dir "+
721 ((newletters==1) ? "einen neuen Brief" : newletters+" neue Briefe")
722 +" in die Hand und verschwindet wieder.\n",78));
Arathorn4c2c85d2020-03-09 23:12:26 +0100723 else
Zesstra25387d92017-02-03 20:20:56 +0100724 write("Du siehst, wie ein Postbeamter "+
725 ((newletters==1) ? "einen neuen Brief" : newletters+" neue Briefe")
726 +" in Dein Fach legt.\n");
727 }
728 GetFolders(1); // jetzt ohne unread, damit im endgueltigen Zustand.
729 while (akt_folder>=sizeof(folders[0])) akt_folder--;
730 if ((!akt_nr)&&sizeof(folders[1][akt_folder])) akt_nr=1;
731}
732
Arathorn4c2c85d2020-03-09 23:12:26 +0100733// MSG_TIME enthaelt leider einen Datumsstring, so dass wir die MSG_ID
734// verwenden, um die Zeit daraus zu ermitteln. Die MSG_ID hat immer das
735// Format MUDNAME+":"+time().
736private string msgIDtoTime(string msg_id) {
737 int msg_time;
Arathorn48c2a4a2022-02-07 22:11:08 +0100738
Arathorn4c2c85d2020-03-09 23:12:26 +0100739 // Damit das auch dann funktioniert, wenn man die Mailfolder aus dem
740 // Livemud im Testmud einliest, das ja ggf. einen anderen Namen hat,
741 // verwenden wir einen generischen Suchstring. Das Mud sollte dann aber
742 // keinen : im Namen haben.
Arathorn48c2a4a2022-02-07 22:11:08 +0100743 if (sscanf(msg_id, "%~s:%d", msg_time) == 2)
Arathorn4c2c85d2020-03-09 23:12:26 +0100744 return strftime("%d.%m.%Y", msg_time);
745 else
746 return "unbekannt";
747}
Zesstra25387d92017-02-03 20:20:56 +0100748
Arathorn4c2c85d2020-03-09 23:12:26 +0100749static varargs void ListContent(int limit) {
Zesstra25387d92017-02-03 20:20:56 +0100750 update();
Arathorn4c2c85d2020-03-09 23:12:26 +0100751
752 if (!pointerp(folders) || sizeof(folders) != 2 ||
753 !pointerp(folders[0]) || !sizeof(folders[0])) {
Zesstra25387d92017-02-03 20:20:56 +0100754 write("Du hast keinen einzigen Ordner!\n");
755 return;
756 }
Arathorn4c2c85d2020-03-09 23:12:26 +0100757
Zesstra25387d92017-02-03 20:20:56 +0100758 write("Ordner "+folders[0][akt_folder]+": ");
Arathorn4c2c85d2020-03-09 23:12:26 +0100759 if (!pointerp(folders[1]) || akt_folder >= sizeof(folders[1]) ||
Zesstra25387d92017-02-03 20:20:56 +0100760 !pointerp(folders[1][akt_folder])) {
761 write("Dieser Ordner ist leer.\n");
762 return;
763 }
Arathorn4c2c85d2020-03-09 23:12:26 +0100764
765 int mailcount = sizeof(folders[1][akt_folder]);
766 write(sprintf("%d Brief%s\n", mailcount, mailcount!=1 ? "e" : ""));
767
768 // Wieviele Zeichen muessen wir fuer die fortlaufenden Mail-Nummern
769 // reservieren? Dazu errechnen wir die Anzahl Ziffern der Arraygroesse.
770 int num_width = sizeof(to_string(mailcount));
771 // 4 Zeichen muessen reichen, damit sind immerhin 9999 Mails numerierbar.
772 num_width = min(4, num_width);
773
774 int sender_width;
775 string sender_name;
776 // Feldbreite fuer die Absenderangabe ermitteln. Wird weiter unten fuer
777 // die Anzeige der Mails benoetigt, um das Namensfeld dynamisch
778 // einzustellen. Dies soll helfen, mehr vom Subject anzeigen zu koennen.
779 // Leider muessen wir dazu einmal extra ueber die Liste laufen.
780 int i;
781 if (limit) {
782 limit = max(mailcount - limit, 0);
783 }
784 for (i = limit ; i < mailcount ; i++) {
785 sender_name = folders[1][akt_folder][i][MSG_FROM];
786 if (sizeof(sender_name) > sender_width)
787 sender_width = sizeof(sender_name);
788 // Wenn wir schon die max. Namenslaenge fuer Spieler erreicht haben,
789 // muss der Rest nicht mehr durchlaufen werden.
790 if (sender_width >= 11) {
791 // Groesse beschraenken; es kann sein, dass alte Mailboxen noch Mails
792 // von extern enthalten, und deren Mailadressen sprengen dann das
793 // Format.
794 sender_width = min(11, sender_width);
795 break;
796 }
797 }
798
799 // Subject-Breite anpassen, je nach Groesse der anderen dynamischen Felder.
800 // sender_width ist max 11, num_width ist max 4.
801 int subject_width = 46+(11-sender_width)+(4-num_width);
802
803 /* Format der Zeile. Wir bauen dynamische Feldbreiten an den Stellen ein,
804 wo es sinnvoll ist, und haben um den Mailzaehler herum zwei String-
805 Felder, die die Markierung fuer die aktuell bearbeitete Mail aufnehmen.
806 Absender und Betreffzeile werden durch den : im Formatcode
807 abgeschnitten. Es muss insbesondere beim Absender der : verwendet
808 werden, damit laengere Namen abgeschnitten werden, bei kuerzeren aber
809 korrekt mit Leerzeichen aufgefuellt wird. Verwendet man stattdessen
810 den ., macht sprintf() das nicht.
811
812 Beispiel einer Zeile mit markierter Mail:
813 [125:](Spielername, 18.12.2019) Test
814 ^_^ ^---------^ ^--^
815 | | |
816 num_width sender_width subject_width */
817 string lineformat = "%s%"+num_width+"d:%s"+ // Mail-Zaehler
818 "(%:"+sender_width+"s, %10s) "+ // Absender + Datum
819 "%:-"+subject_width+"s\n"; // Betreffzeile
820
821 for (i = limit ; i < mailcount ; i++) {
822 // Leeres Subject wird als 0 gespeichert. Falls das zutrifft, wird das
823 // hier beruecksichtigt.
824 string subject = folders[1][akt_folder][i][MSG_SUBJECT];
825 if (!stringp(subject) || !sizeof(subject))
826 subject = "<kein Betreff>";
827 write(sprintf(lineformat,
828 (i+1==akt_nr) ? "[" : " ",
829 i+1,
830 (i+1==akt_nr) ? "]" : " ",
831 capitalize(folders[1][akt_folder][i][MSG_FROM]),
832 msgIDtoTime(folders[1][akt_folder][i][MSG_ID]),
833 subject
834 ));
Zesstra25387d92017-02-03 20:20:56 +0100835 }
836 return;
837}
838
839
Arathorn4c2c85d2020-03-09 23:12:26 +0100840static void ChangeFolder(mixed x) {
Zesstra25387d92017-02-03 20:20:56 +0100841 if (!(x=GetFolderName(x))) return;
842 akt_folder=member(folders[0],x);
843 write("Du oeffnest den Ordner '"+x+"'.\n");
844 if (akt_nr<=0) akt_nr=1;
Arathorn4c2c85d2020-03-09 23:12:26 +0100845 if (akt_nr>=sizeof(folders[1][akt_folder]))
Zesstra25387d92017-02-03 20:20:56 +0100846 akt_nr=sizeof(folders[1][akt_folder]);
847 ListContent();
848}
849
850
851static void ListFolders() {
852 int i;
853 update();
854 write("Du hast "+sizeof(folders[0])+" Ordner:\n");
855 for (i=0;i<sizeof(folders[0]);i++)
856 write(sprintf("%2s%3d: %-20s(%3d Briefe)\n",
857 ((i==akt_folder)?"->":" "),
858 i+1,folders[0][i],sizeof(folders[1][i])));
859 write("Gesamtgroesse Deines Postfachs: "+
860 ((file_size(MAILFILEO(name))+512)/1024)+" KB.\n");
861}
862
863
864static void MakeFolder(string s) {
865 int ret;
866 if (sscanf(s,"%d",ret)||s[0]<'a'||s[0]>'z') return
867 write("Um Probleme zu vermeiden, duerfen Ordner nicht mit Nummern oder Sonderzeichen\nbezeichnet werden.\n");
868 if (s=="newmail"||s=="unread") return
869 write("Die Ordnernamen 'newmail' und 'unread' sind reserviert.\n");
870 ret=MAILDEMON->MakeFolder(s, name);
871 if (ret==1) write("Ok, neuer Ordner mit Namen "+s+" angelegt.\n");
872 else write("Ein Ordner mit dem Namen existiert bereits.\n");
873 return;
874}
875
876
877static int RemoveFolder(string x) {
878 int ret;
879 if (!x) return -42; // folder existiert nicht, Fehlermeldung bereits geg.
880// if (intp(x)) x=folders[0][x];
881
882 if (x=="newmail") return
883 write("Der Ordnername 'newmail' ist reserviert.\nDieser Ordner darf nicht geloescht werden.\n"),-43;
884
885 ret=MAILDEMON->RemoveFolder(x, name);
886 switch (ret) {
887 case 1: write("Ordner "+x+" geloescht.\n"); break;
888 case -1: write("Kein solcher Ordner.\n"); break;
889 case 0: write("Der Ordner war nicht leer - nicht geloescht.\n"); break;
890 default: write("Fehler Nummer "+ret+" - was auch immer das heisst...\n"); break;
891 }
892 return ret;
893}
894
895
896static varargs int DeleteMessage(int *nrs) {
897 int ret,x;
Arathorn48c2a4a2022-02-07 22:11:08 +0100898
Zesstra25387d92017-02-03 20:20:56 +0100899 if ( sizeof(nrs) > 15 ) LagWarning();
900
901 for (x=sizeof(nrs)-1;x>=0;x--) {
902 write("Loesche Brief "+(nrs[x]+1)+": ");
903 ret=MAILDEMON->RemoveMsg(nrs[x], akt_folder, name);
904 switch(ret) {
905 case 1: write("Ok.\n"); break;
906 case 0: write("Kein solcher Brief im aktuellen Ordner.\n"); break;
907 case -1:write("Kein aktueller Ordner.\n"); update(); return ret;
908 default: write("MAILDEMON: Interner Fehler Nummer "+ret+"!\n"); break;
909 }
910 }
Arathorn4c2c85d2020-03-09 23:12:26 +0100911
Zesstra25387d92017-02-03 20:20:56 +0100912 return ret;
913}
914
915//"
916
917static int MoveMessage(mixed msg,mixed fol) {
918 int ret,i;
Arathorn4c2c85d2020-03-09 23:12:26 +0100919
Zesstra25387d92017-02-03 20:20:56 +0100920 for (i=0;i<sizeof(msg);i++) {
921 ret=MAILDEMON->MoveMsg(msg[i]-i, akt_folder, fol, name);
922 switch(ret) {
923 case 1:
924 write("Brief "+(msg[i]+1)+" verschoben nach "+fol+".\n");
925 break;
Arathorn4c2c85d2020-03-09 23:12:26 +0100926 case 0:
Zesstra25387d92017-02-03 20:20:56 +0100927 write("So viele Briefe sind nicht im aktuellen Ordner.\n"); return 0;
928 case -1:
929 write("Seltsamer Fehler - duerfte eigentlich nicht passieren:\n'Kein aktueller Ordner.'\n"); return -1;
930 case -3:
931 write("Den Zielordner "+fol+" gibt es nicht!\n"); return ret;
932 default:
933 write("MAILDEMON: MoveMsg Interner Fehler "+ret+". Bitte Erzmagier verstaendigen.\n"); return ret;
934 }
935 }
Arathorn4c2c85d2020-03-09 23:12:26 +0100936 if (akt_nr>=sizeof(folders[1][akt_folder]))
Zesstra25387d92017-02-03 20:20:56 +0100937 akt_nr=sizeof(folders[1][akt_folder])-1;
Arathorn4c2c85d2020-03-09 23:12:26 +0100938
Zesstra25387d92017-02-03 20:20:56 +0100939 return ret;
940}
941
942
943static varargs int Reply(int nr,int group) {
Arathorn48c2a4a2022-02-07 22:11:08 +0100944 mixed to;
Zesstra25387d92017-02-03 20:20:56 +0100945 if (!pointerp(folders)||!pointerp(folders[0])||
946 sizeof(folders[0])<=akt_folder) {
947 write("Seltsamer Fehler: Kein aktueller Ordner!\n");
948 return 0;
949 }
950 if (nr<0 || !pointerp(folders[1][akt_folder]) ||
951 sizeof(folders[1][akt_folder])<=nr){
952 write("Einen Brief mit Nummer "+(nr+1)+" gibt es in diesem Ordner nicht!\n");
953 return 0;
954 }
955
956 if (sscanf("\n"+lower_case(folders[1][akt_folder][nr][MSG_BODY]),
Arathorn48c2a4a2022-02-07 22:11:08 +0100957 "%~s\nreply-to:%s\n",to)==2) { // Reply-to gesetzt
Zesstra25387d92017-02-03 20:20:56 +0100958 while (to[0]==' ') to=to[1..]; // ueberschuessige Leerzeichen entfernen
959 while (to[<1]==' ') to=to[0..<2];
960 }
Arathorn4c2c85d2020-03-09 23:12:26 +0100961 else
Zesstra25387d92017-02-03 20:20:56 +0100962 to=folders[1][akt_folder][nr][MSG_FROM];
963 if (group) // Gruppenantwort
964 to=({to,
965 folders[1][akt_folder][nr][MSG_RECIPIENT]})+
966 (pointerp(folders[1][akt_folder][nr][MSG_CC]) ? folders[1][akt_folder][nr][MSG_CC] : ({}))
967 -({name});
968#ifdef DEBUG
969 DEBUGVAR(name);
970 DEBUGVAR(to);
971#endif
972 write_mail(to,GetReTitle(folders[1][akt_folder][nr][MSG_SUBJECT]));
973 return 1;
974}
975
976
977static varargs int Forward(mixed to,mixed nr,int appendflag) {
Zesstra25387d92017-02-03 20:20:56 +0100978 if (!pointerp(folders)||!pointerp(folders[0])||
979 sizeof(folders[0])<=akt_folder) {
980 write("Seltsamer Fehler: Kein aktueller Ordner!\n");
981 return 0;
982 }
983 if (nr<0 || !pointerp(folders[1][akt_folder]) ||
984 sizeof(folders[1][akt_folder])<=nr){
985 write("Nicht so viele Briefe in diesem Ordner!\n");
986 return 0;
987 }
988 to=process_names(to);
989 receiver=to[0];
990 carbon=to[1..];
991 subject="Fw: "+folders[1][akt_folder][nr][MSG_SUBJECT];
992 message="Weitergesendeter Brief, urspruenglich von: "+
993 folders[1][akt_folder][nr][MSG_FROM]+"\n\
994-----------------------------\n\
995"+folders[1][akt_folder][nr][MSG_BODY]+"\
996-----------------------------\n";
997 if (!appendflag) return get_carbon_copy(0),1;
998 else {
999 write("Text kann angehaengt werden\n");
1000 get_subject(subject,message);
1001 }
1002 return 1;
1003}
1004
1005
1006
1007static int ForwardArea(mixed to,int * nrs) {
Zesstra25387d92017-02-03 20:20:56 +01001008
1009 if (!sizeof(nrs)) return 0;
1010 if (sizeof(nrs)==1) return Forward(to,nrs[0]);
1011 if (sizeof(nrs)>15) LagWarning();
1012
1013 to=process_names(to);
1014 receiver=to[0];
1015 carbon=to[1..];
1016 subject="Fw: Gesammelte Briefe ("+dtime(time())[5..23]+")";
1017 message="";
1018 for (i=0;i<sizeof(nrs);i++) {
1019 write("Brief "+(nrs[i]+1)+": ");
1020 message+=Message2string(nrs[i])+
1021 "----------------------------------------------------------------------\n";
1022 write("Angehaengt.\n");
1023 }
1024/*
1025 if (!appendflag) {
1026*/
1027 return get_carbon_copy(0),1;
1028/* }
1029 else {
1030 write("Text kann angehaengt werden\n");
1031 get_subject(subject,message);
1032 }
1033 return 1;
1034*/
1035}
1036
1037//----------
1038
1039
1040static int ReadMessage(int nr) {
1041 if (nr<sizeof(folders[1][akt_folder]) && nr>=0)
1042 akt_nr=nr+1;
1043 message=Message2string(nr);
1044 if (!message) return 0;
1045 this_player()->More(message,0,#'input); //')
1046 return 1;
1047}
1048
1049
1050static string Message2string(int nr) {
1051 mixed letter;
1052 string message;
Arathorn48c2a4a2022-02-07 22:11:08 +01001053
Zesstra25387d92017-02-03 20:20:56 +01001054 if (!pointerp(folders)||!pointerp(folders[0])||
1055 sizeof(folders[0])<=akt_folder){
1056 write("Seltsamer Fehler: Kein aktueller Ordner!\n");
1057 return 0;
1058 }
1059 if (!pointerp(folders[1][akt_folder]) ||
1060 sizeof(folders[1][akt_folder])<=nr ||
1061 nr<0) {
1062 write("Diese Nummer gibt es in diesem Ordner nicht!\n");
1063 return 0;
1064 }
1065 letter=folders[1][akt_folder][nr];
1066 message=
1067 "Absender: "+capitalize(letter[MSG_FROM])+"\n"+
1068 ((letter[MSG_FROM]==letter[MSG_SENDER]) ? "" :
1069 "Abgesandt aber von: "+capitalize(letter[MSG_SENDER])+"\n") +
1070 "An: "+capitalize(letter[MSG_RECIPIENT]);
1071 if (stringp(letter[MSG_CC]) && letter[MSG_CC]!="" ||
1072 pointerp(letter[MSG_CC]) && sizeof(letter[MSG_CC])) {
1073 message+="\nCc: ";
Arathorn4c2c85d2020-03-09 23:12:26 +01001074 if (!pointerp(letter[MSG_CC])) message+=capitalize(letter[MSG_CC]);
Zesstra25387d92017-02-03 20:20:56 +01001075 else message+=implode(map(letter[MSG_CC],#'capitalize),", ");//'))
1076 }
1077 message+="\nDatum: "+letter[MSG_DATE]+"\n"+
1078/* Sinnlos, oder? "Id: "+letter[MSG_ID]+"\n"+ */
1079 "Titel: "+letter[MSG_SUBJECT]+"\n\n"+
1080 letter[MSG_BODY]+"\n\n";
1081 return message;
1082}
1083
1084
1085static void LagWarning() {
1086 write("\
1087WARNUNG!!! Diese Aktion kann sehr lange benoetigen. Bitte sparsam verwenden,\n\
1088 um das Lag fuer alle ertraeglich zu halten. Falls die Aktion mit einem\n\
1089 Fehler abbricht, waren es wahrscheinlich zu viele Briefe auf einmal.\n\
1090 Dann kannst Du mit \"mail\" wieder in das Mailmenu einsteigen und solltest\n\
1091 es mit weniger Briefen versuchen.\n");
1092}
1093
1094
1095static varargs int SaveMessage(int * nrs) {
Arathorn48c2a4a2022-02-07 22:11:08 +01001096 int nr;
Zesstra25387d92017-02-03 20:20:56 +01001097 mixed letter;
1098
1099 if (!IS_WIZARD(this_player())) {
1100 write("Das koennen nur Magier!\n");
1101 return 0;
1102 }
1103 if (!sizeof(nrs)) {
1104 write("Speichere nichts.\n");
1105 return 1;
1106 }
Arathorn4c2c85d2020-03-09 23:12:26 +01001107
Zesstra25387d92017-02-03 20:20:56 +01001108 if ( sizeof(nrs) > 15 ) LagWarning();
1109
1110 for (nr=0;nr<sizeof(nrs);nr++) {
1111 write("Speichere Brief "+(nrs[nr]+1)+": ");
1112 letter=Message2string(nrs[nr]);
1113 letter+="----------------------------------------------------------------------\n";
1114 if (!letter) {
1115 write("Speichern unmoeglich.\n");
1116 return 0;
1117 }
1118 if (!write_file(SAVEFILENAME, letter))
1119 write("Brief zu lang!\n");
1120 else
1121 write("Ok.\n");
1122 }
1123 write("Speichern nach "+SAVEFILENAME+" fertig.\nBitte denk dran, diese Datei wieder zu loeschen!\n");
1124 return 1;
1125}
1126
1127// {'}
1128
1129static void ListAliases() {
1130 mixed a;
1131 int i;
1132 string s;
1133 a=sort_array(m_indices(aliases),#'>); // ');
1134 s=( "Definierte Aliase:\n"
Zesstra25387d92017-02-03 20:20:56 +01001135 "freunde = Deine Freunde (entsprechend Freundschaftsband)\n"
1136 "me = "+(this_player()->QueryProp(P_MAILADDR))+"\n");
Arathorn4c2c85d2020-03-09 23:12:26 +01001137 for (i=0;i<sizeof(a);i++)
Zesstra25387d92017-02-03 20:20:56 +01001138 if (strstr(aliases[a[i]],"@")==-1) s+=sprintf("%-12s = %s\n",a[i],aliases[a[i]]);
1139 write(s);
1140}
1141
1142
1143
1144/* ------ Das Mailmenue --------------------------------------------------*/
1145
1146
1147static void mail_cmds(string str) {
Zesstra25387d92017-02-03 20:20:56 +01001148 string *strargs;
Arathorn48c2a4a2022-02-07 22:11:08 +01001149 int nrargs;
Arathorn4c2c85d2020-03-09 23:12:26 +01001150
Zesstra25387d92017-02-03 20:20:56 +01001151 update();
1152
1153 if (!str || str=="" || !(nrargs=sizeof(strargs=old_explode(str[0..0]+lower_case(str[1..])," ")))) {
1154 ListContent();
1155 return input();
1156 }
1157 strargs[0]=strargs[0][0..3];
1158 if (IS_NUMBER(strargs[0])) {
1159 strargs=({"lies",strargs[0]});
1160 nrargs=2;
1161 }
1162 DEBUGVAR(strargs);
1163 switch (strargs[0]) {
1164 case "q": // quit
Arathorn4c2c85d2020-03-09 23:12:26 +01001165 case "quit":
Zesstra25387d92017-02-03 20:20:56 +01001166 remove(); return;
1167 case "?": // Hilfeseite
1168 case "hilf":
1169 case "h":
1170 MediumHelpPage();
1171 return;
1172 case "oeff": // change folder
Arathorn4c2c85d2020-03-09 23:12:26 +01001173 case "c":
Zesstra25387d92017-02-03 20:20:56 +01001174 if (nrargs<2) {
1175 write("Welchen Ordner willst Du oeffnen (Name, Nummer, +, -)?\n");
1176 break;
1177 }
1178 ChangeFolder(strargs[1]);
1179 break;
1180 case "ordn": // list folders
Arathorn4c2c85d2020-03-09 23:12:26 +01001181 case "i":
Zesstra25387d92017-02-03 20:20:56 +01001182 ListFolders();
1183 break;
1184 case "anze": // list content
1185 case "l":
1186 ListContent();
1187 break;
1188 case "alia": // list aliases
1189 case "a":
1190 ListAliases();
1191 break;
1192 case "erze": // make new folder
Arathorn4c2c85d2020-03-09 23:12:26 +01001193 case "n":
Zesstra25387d92017-02-03 20:20:56 +01001194 if (nrargs<2) {
1195 write("Bitte als Argument einen Namen fuer den neuen Ordner angeben!\n");
1196 break;
1197 }
1198 MakeFolder(lower_case(strargs[1]));
1199 break;
1200 case "entf": // delete folder
Arathorn4c2c85d2020-03-09 23:12:26 +01001201 case "e":
Zesstra25387d92017-02-03 20:20:56 +01001202 if (nrargs<2) {
1203 write("Bitte als Argument Name oder Nummer des zu loeschenden Ordners angeben.\n");
1204 break;
1205 }
1206 RemoveFolder(GetFolderName(strargs[1]));
1207 break;
1208 case "loes": // delete message
1209 case "d":
1210 if (nrargs==1) DeleteMessage(({akt_nr-1}));
1211 else DeleteMessage(GetNumbers(strargs[1..]));
1212 break;
1213 case "schr": // write mail
Arathorn4c2c85d2020-03-09 23:12:26 +01001214 case "m":
Zesstra25387d92017-02-03 20:20:56 +01001215 if (nrargs<2) {
1216 write("Bitte Empfaenger als Argument angeben!\n");
1217 break;
1218 }
1219 write_mail(strargs[1..]);
1220 return;
1221 case "vers": // move message to other folder
1222 case "verl":
1223 case "v":
1224 if (nrargs<2 || (nrargs>2 && !IS_NUMBER(strargs[1]))) {
1225 write("Syntax: v [nr|nr-nr [nr|nr-nr ...]] <ordnername>|<ordnernr>|+|-\n");
1226 break;
1227 }
1228 if (nrargs==2) MoveMessage(({akt_nr-1}),GetFolderName(strargs[1]));
1229 else MoveMessage(GetNumbers(strargs[1..<2]),GetFolderName(strargs[<1]));
1230 update(0,1); // unbedingt neuladen.
1231 break;
1232 case "bean":
1233 case "r":
1234 case "grup":
1235 case "g":
Arathorn4c2c85d2020-03-09 23:12:26 +01001236 if (nrargs<2) {
Zesstra25387d92017-02-03 20:20:56 +01001237 if (Reply(akt_nr-1,(strargs[0][0]=='g'))) return;
1238 break;
1239 }
1240 if (!IS_NUMBER(strargs[1])) {
1241 write("Argumentfehler: Bitte Nummer des Briefes angeben, auf den sich die Antwort\n"
1242 "beziehen soll. Ohne Argument bezieht sie sich auf den aktuellen Brief.\n");
1243 break;
1244 }
1245 if (nrargs>2) {
1246 write("Zu viele Argumente. Eine Antwort darf sich nur auf einen Brief beziehen!\n");
1247 break;
1248 }
1249 if (Reply(to_int(strargs[1])-1,(strargs[0][0]=='g'))) return;
1250 break;
1251 case "weit":
1252 case "f":
Arathorn4c2c85d2020-03-09 23:12:26 +01001253 if (nrargs<2 ||
Zesstra25387d92017-02-03 20:20:56 +01001254 (IS_NUMBER(strargs[nrargs-1])&&sizeof(old_explode(strargs[nrargs-1],"@"))==1)) {
1255 write("Syntax: f [nr|nr-nr [nr|nr-nr ...]] empfaenger [empf2 ...]\n");
1256 break;
Arathorn4c2c85d2020-03-09 23:12:26 +01001257 }
Zesstra25387d92017-02-03 20:20:56 +01001258 if (!IS_NUMBER(strargs[1])) {
Arathorn4c2c85d2020-03-09 23:12:26 +01001259 if (Forward(strargs[1..],akt_nr-1)) return;
Zesstra25387d92017-02-03 20:20:56 +01001260 } // return, nicht break: input() wird von get_carbon_copy() aufger.
1261 else {
1262 int pos; // letzte Position, an der eine Nummer steht
Arathorn4c2c85d2020-03-09 23:12:26 +01001263
Zesstra25387d92017-02-03 20:20:56 +01001264 for (pos=nrargs-1;pos>1&&!IS_NUMBER(strargs[pos]);pos--);
1265 if (ForwardArea(strargs[(pos+1)..],GetNumbers(strargs[1..pos])))
1266 return;
Arathorn4c2c85d2020-03-09 23:12:26 +01001267 }
Zesstra25387d92017-02-03 20:20:56 +01001268 break;
1269 case "Weit":
1270 case "F":
1271 if (nrargs<2 || (nrargs==2 && IS_NUMBER(strargs[1]))) {
1272 write("Haeh? Bitte so: F [nr] empfaenger\n");
1273 break;
1274 }
1275 if (!IS_NUMBER(strargs[1])) {
1276 if (Forward(strargs[1..],akt_nr-1,1)) return;
1277 break;
1278 }
1279 if (IS_NUMBER(strargs[2])||member(strargs[1],'-')>=0) {
1280 write("Argumentfehler: Wenn Du eigenen Text anhaengen willst, darfst Du nur einen\n"
1281 "Brief angeben, nicht mehrere.\n");
1282 break;
1283 }
1284 if (Forward(strargs[2..],to_int(strargs[1])-1,1)) return;
1285 break;
1286 case "lies":
1287 if (nrargs<2) { if (ReadMessage(akt_nr-1)) return; } else
1288 if (ReadMessage(to_int(strargs[1])-1)) return;
1289 break;
1290 case ".":
1291 if (ReadMessage(akt_nr-1)) return;
1292 break;
1293 case "+":
1294 if (akt_nr==sizeof(folders[1][akt_folder]))
1295 write("Noch weiter vorwaerts gehts nicht!\nMit 'c +' kannst Du den naechsten Ordner oeffnen.\n");
1296 else if (ReadMessage(akt_nr)) return;
1297 break;
1298 case "-":
1299 if (akt_nr==1)
1300 write("Noch weiter zurueck gehts nicht!\nMit 'c -' kannst Du den vorhergehenden Ordner oeffnen.\n");
1301 else if (ReadMessage(akt_nr-2)) return;
1302 break;
1303 case "spei":
1304 case "s":
Arathorn484b92c2022-02-07 22:11:31 +01001305 // Fallthrough fuer Nichtmagier auf "nicht verstanden"
1306 if (IS_WIZARD(this_player())) {
1307 if ((nrargs==2 && !IS_NUMBER(strargs[1]))) {
1308 write("Syntax: s [nr|nr-nr [nr|nr-nr ...]]\n");
1309 break;
1310 }
1311 if (nrargs==1) (SaveMessage(({akt_nr-1})));
1312 else (SaveMessage(GetNumbers(strargs[1..])));
Zesstra25387d92017-02-03 20:20:56 +01001313 break;
1314 }
Zesstra25387d92017-02-03 20:20:56 +01001315 default:
1316 write("Kommando nicht verstanden. Eine Hilfsseite bekommst Du mit 'h'.\n");
1317 break;
1318 }
1319 return input();
1320}
1321
1322
1323/*------------------------------------------------------------------------*/
1324
1325static string prompt() {
1326 string path;
Arathorn4c2c85d2020-03-09 23:12:26 +01001327
Zesstra25387d92017-02-03 20:20:56 +01001328 update();
1329 if (!pointerp(folders)||!pointerp(folders[0])||
1330 sizeof(folders[0])<=akt_folder)
1331 path="(kein Ordner)";
1332 else
1333 path= "(" + folders[0][akt_folder] + ":" +
1334 ( sizeof(folders[1][akt_folder]) ?
1335 akt_nr + "/" + sizeof(folders[1][akt_folder]) :
1336 "leer") + ")";
1337 return(path + " [Hilfe mit h] => ");
1338}
1339
1340
1341static void input() {
1342 //prompt();
1343 input_to("mail_cmds", INPUT_PROMPT, prompt());
1344 return;
1345}
1346
1347
1348static mixed GetAlias(mixed a);
1349
1350#ifdef MAIL_SUPPORT_BCC
1351static mixed RecurseProcessNames(mixed a);
1352#endif
1353
1354
1355static mixed process_names(mixed s) {
Arathorn48c2a4a2022-02-07 22:11:08 +01001356 mixed a1,a2;
Zesstra25387d92017-02-03 20:20:56 +01001357
1358 if (stringp(s)) {
1359 a1=explode(regreplace(lower_case(s),","," ",1)," ")-({""});
1360 }
1361 else a1=s;
1362 a2=({});
1363 foreach(string str: a1)
1364 a2+=explode(str,",");
1365
1366 a1=({});
1367
1368// printf("DEBUG ANFANG: %O\n",a2);
1369
Arathorn0a8e4d32020-07-29 18:36:59 +02001370 foreach(string str: a2)
1371 {
1372 if (str=="freunde")
1373 a1 += ("/p/service/tiamak/obj/fbmaster"->get_friends(
1374 getuid(this_player()), 8));
1375 else if (str=="me")
1376 a1+=({this_player()->QueryProp(P_MAILADDR)});
1377 else if (aliases[str])
1378 a1+=GetAlias(str);
Zesstra25387d92017-02-03 20:20:56 +01001379#ifdef MAIL_SUPPORT_BCC
1380 else if (str[0]=='-')
Arathorn0a8e4d32020-07-29 18:36:59 +02001381 a1+=map(RecurseProcessNames(str[1..]), function string (string x) {
1382 return("-"+x);
1383 });
Zesstra25387d92017-02-03 20:20:56 +01001384#endif
Arathorn0a8e4d32020-07-29 18:36:59 +02001385 else if ( (str[0]>='a' && str[0]<='z') ||
Arathorn48c2a4a2022-02-07 22:11:08 +01001386 sscanf(str,"%~s@%~s") ||
Arathorn0a8e4d32020-07-29 18:36:59 +02001387 str[0]=='\\')
1388 a1+=({str});
Zesstra25387d92017-02-03 20:20:56 +01001389 }
Arathorn4c2c85d2020-03-09 23:12:26 +01001390
Zesstra25387d92017-02-03 20:20:56 +01001391// printf("DEBUG ENDE: %O\n",a1);
1392
Arathorn0a8e4d32020-07-29 18:36:59 +02001393 a1=filter(a1, function int (string x) {
1394 return(sizeof(x)>1);
1395 });
Zesstra25387d92017-02-03 20:20:56 +01001396
1397 return(map(a1,#'lower_case));
Arathorn4c2c85d2020-03-09 23:12:26 +01001398}
Zesstra25387d92017-02-03 20:20:56 +01001399
1400
1401static mixed GetAlias(mixed a) { return process_names(aliases[a]); }
1402#ifdef MAIL_SUPPORT_BCC
1403static mixed RecurseProcessNames(mixed a) { return process_names(a); }
1404#endif
1405
1406
1407static mapping Read_mailrc(string file) {
1408 mapping al;
1409 int i;
1410 mixed ar;
1411 string s1,s2;
1412
1413 if (!(ar=read_file(file))) {
1414// write(file+" not readable\n");
1415 return ([]);
1416 }
1417 al=([]);
1418 ar=explode(ar,"\n");
1419 for (i=sizeof(ar)-1;i>=0;i--)
Arathorn4c2c85d2020-03-09 23:12:26 +01001420 if (sscanf(ar[i],"%s %s",s1,s2)==2)
Zesstra25387d92017-02-03 20:20:56 +01001421 al+=([s1:s2]);
1422// printf("Got aliases %O",al);
1423 return al;
1424}
1425
1426
1427string * unify_array(string * a) {
1428// int i;
1429// for (i=sizeof(a)-1;i>=0;i--) a=a-({a[i]})+({a[i]});
1430// Rikus 14.02.2001
1431 a=m_indices(mkmapping(a));
1432 return a;
1433}
1434
1435
1436string GetReTitle(string s) {
1437 int nr,s2;
1438
1439 if (!s) s="";
1440 if (s[0..7]=="Re: Re: ") return "Re^3: "+s[8..];
1441 else if (sscanf(s,"Re^%d: %s",nr,s2))
1442 return "Re^"+(nr+1)+": "+s2;
1443 else return "Re: "+s;
1444}
1445
1446
1447int * GetNumbers(mixed s) {
1448 int i,h1,h2;
1449 mixed ret;
Arathorn4c2c85d2020-03-09 23:12:26 +01001450
Zesstra25387d92017-02-03 20:20:56 +01001451 if (intp(s)) return ({s-1});
1452 if (stringp(s)) s=({s-1});
1453 if (!pointerp(s)) return 0;
1454
1455 ret=({});
1456
1457 for (i=sizeof(s)-1;i>=0;i--) {
1458 if (sscanf(s[i],"%d-%d",h1,h2)==2) {
1459 if (h2-h1>100) {
1460 write("Nicht so viele auf einmal, bitte.\n");
1461 return ({});
1462 }
1463 for (h1--;h1<h2;h1++) ret=ret-({h1})+({h1});
1464 }
1465 else
1466 ret=ret-({h1=to_int(s[i])-1})+({h1});
1467 }
1468 ret=sort_array(ret,#'>); //')
1469 DEBUGVAR(ret);
1470 if (ret[0]<0) {
1471 write("Illegale Nummer: "+(ret[0]+1)+", nichts unter 1 bitte!\n");
1472 return ({});
1473 }
1474 if (ret[<1]>=sizeof(folders[1][akt_folder])) {
1475 write("Illegale Nummer: "+(ret[<1]+1)+", so gross ist dieser Ordner nicht!\n");
1476 return ({});
1477 }
1478 return ret;
1479}
1480
1481
1482/*
1483int is_number(string s) {
1484 return (s[0]>='0'&&s[0]<='9');
1485}
1486*/
1487
1488
1489string GetFolderName(mixed fol) { // int oder string. alles andere -> Fehler!
1490 mixed h;
1491
1492 if (fol=="+") fol=akt_folder+1;
1493 if (fol=="-") fol=akt_folder-1;
1494 if ((!fol)||(intp(fol))||(IS_NUMBER(fol))) {
1495 if (!intp(fol)) fol=to_int(fol)-1;
Arathorn4c2c85d2020-03-09 23:12:26 +01001496 if (fol<0||fol>=sizeof(folders[0]))
Zesstra25387d92017-02-03 20:20:56 +01001497 return write("Einen Ordner mit Nummer "+(fol+1)+" gibt es nicht.\n"),0;
1498 return folders[0][fol];
1499 }
1500 fol=lower_case(fol);
1501 if (sizeof(h=regexp(folders[0],"^"+fol))==1) return h[0];
1502 if (member(folders[0],fol)==-1)
1503 return write("Einen Ordner mit Namen "+fol+" hast Du nicht.\n"),0;
1504 return fol;
1505}
1506
1507int query_prevent_shadow() { return 1; }