/secure/errord.c.orig entfernt.
Versentlich in nen Commit geraten...
Change-Id: Ib40bca35ab56b1c57bf48b07e88b324ce8e0ca5b
diff --git a/secure/errord.c.orig b/secure/errord.c.orig
deleted file mode 100644
index bb4ac10..0000000
--- a/secure/errord.c.orig
+++ /dev/null
@@ -1,1529 +0,0 @@
-/* MorgenGrauen MUDlib
- /p/daemon/errord.c
- speichert Fehler und Warnungen
- Autor: Zesstra
- $Id: errord.c 9439 2016-01-20 09:48:28Z Zesstra $
- ggf. Changelog:
-*/
-
-#pragma strict_types,save_types,rtt_checks
-#pragma no_clone
-#pragma no_shadow
-#pragma no_inherit
-#pragma pedantic
-#pragma range_check
-#pragma warn_deprecated
-
-#include <config.h>
-#include <wizlevels.h>
-#include <defines.h>
-#include <debug_info.h>
-#include <commands.h>
-#include <wizlevels.h>
-#include <mail.h>
-#include <tls.h>
-#include <events.h>
-
-inherit "/secure/errord-structs";
-
-#define __NEED_IMPLEMENTATION__
-#include "errord.h"
-#undef __NEED_IMPLEMENTATION__
-
-#define SAVEFILE (__DIR__+"ARCH/errord")
-
-#define TI this_interactive()
-
-private int access_check(string uid,int mode);
-private varargs int set_lock(int issueid, int lock, string note);
-private varargs int set_resolution(int issueid, int resolution, string note);
-public string* print_type(int type);
-
-private int versende_mail(struct fullissue_s fehler);
-
-nosave mapping lasterror; // die letzen 5 jeder Art.
-
-
-/* ******************* Helfer **************************** */
-
-public int getErrorID(string hashkey)
-{
- int** row=sl_exec("SELECT id from issues WHERE hashkey=?1;",
- hashkey);
- //DEBUG(sprintf("getEID: %s: %O\n",hashkey,row));
- if (pointerp(row))
- {
- return row[0][0];
- }
- return -1;
-}
-
-// note->id muss auf einen Eintrag in issues verweisen, es erfolgt keine
-// Pruefung.
-int db_add_note(struct note_s note)
-{
- sl_exec("INSERT INTO notes(issueid,time,user,txt) "
- "VALUES(?1,?2,?3,?4);",
- to_array(note)...);
- return sl_insert_id();
-}
-
-private struct frame_s* db_get_stack(int issueid)
-{
- mixed rows = sl_exec("SELECT * FROM stacktraces WHERE issueid=?1 "
- "ORDER BY rowid;", issueid);
- if (pointerp(rows))
- {
- struct frame_s* stack = allocate(sizeof(rows));
- int i;
- foreach(mixed row : rows)
- {
- stack[i] = to_struct(row, (<frame_s>));
- ++i;
- }
- return stack;
- }
- return 0;
-}
-
-private struct note_s* db_get_notes(int issueid)
-{
- mixed rows = sl_exec("SELECT * FROM notes WHERE issueid=?1 "
- "ORDER BY rowid;", issueid);
- if (pointerp(rows))
- {
- struct note_s* notes = allocate(sizeof(rows));
- int i;
- foreach(mixed row : rows)
- {
- notes[i] = to_struct(row, (<note_s>));
- ++i;
- }
- return notes;
- }
- return 0;
-}
-
-// einen durch id oder hashkey bezeichneten Eintrag als fullissue_s liefern.
-private struct fullissue_s db_get_issue(int issueid, string hashkey)
-{
- mixed rows = sl_exec("SELECT * FROM issues WHERE id=?1 OR hashkey=?2;",
- issueid, hashkey);
- if (pointerp(rows))
- {
- // Einfachster Weg - funktioniert aber nur, solange die Felder in der DB
- // die gleiche Reihenfolge wie in der struct haben! Entweder immer
- // sicherstellen oder Ergebnisreihenfolge oben im select festlegen!
- struct fullissue_s issue = to_struct( rows[0], (<fullissue_s>) );
- if (issue->type == T_RTERROR)
- issue->stack = db_get_stack(issue->id);
- issue->notes = db_get_notes(issue->id);
- return issue;
- }
- return 0;
-}
-
-private struct fullissue_s filter_private(struct fullissue_s issue)
-{
- //momentan wird F_CLI, also die Spielereingabe vor dem Fehler
- //ausgefiltert, wenn TI kein EM oder man in process_string() ist.
-
- //Wenn EM und nicht in process_string() oder die Spielereingabe gar nicht
- //im Fehlereintrag drinsteht: ungefiltert zurueck
- if (!issue->command ||
- (!process_call() && ARCH_SECURITY) )
- return issue;
-
- //sonst F_CLI rausfiltern, also Kopie und in der Kopie aendern.
- issue->command="Bitte EM fragen";
- return issue;
-}
-
-// setzt oder loescht die Loeschsperre.
-// Prueft, ob <issueid> existiert und aendert den Zustand nur, wenn noetig.
-// Rueckgabe: -1, wenn Issue nicht existiert, -2 wenn bereits resolved, -3
-// wenn keine Aenderung noetig, sonst den neuen Sperrzustand
-int db_set_lock(int issueid, int lockstate, string note)
-{
- int** rows = sl_exec("SELECT locked,resolved FROM issues WHERE id=?1;",
- issueid);
- if (!rows)
- return -1; // nicht vorhanden.
-
- if (rows[0][1])
- return -2; // bereits resolved -> Sperre nicht moeglich.
-
-
- if (lockstate && !rows[0][0])
- {
- // Sperren
-// sl_exec("BEGIN TRANSACTION;");
- sl_exec("UPDATE issues SET locked=1,locked_by=?2,locked_time=?3,mtime=?3 "
- "WHERE id=?1;",
- issueid, getuid(TI), time());
- db_add_note( (<note_s> id: issueid, time: time(), user: getuid(TI),
- txt: sprintf("Lock gesetzt: %s",
- note ? note : "<kein Kommentar>")) );
-// sl_exec("COMMIT;");
- return 1;
- }
- else if (!lockstate && rows[0][0])
- {
- // entsperren
-// sl_exec("BEGIN TRANSACTION;");
- sl_exec("UPDATE issues SET locked=0,locked_by=0,locked_time=0,mtime=?2 "
- "WHERE id=?1;", issueid, time());
- db_add_note( (<note_s> id: issueid, time: time(), user: getuid(TI),
- txt: sprintf("Lock geloescht: %s",
- note ? note : "<kein Kommentar>")) );
-// sl_exec("COMMIT;");
- return 0;
- }
- // nix aendern.
- return -3;
-}
-
-// markiert ein Issue als gefixt oder nicht gefixt.
-// Prueft, ob <issueid> existiert und aendert den Zustand nur, wenn noetig.
-// Rueckgabe: -1, wenn Issue nicht existiert, -3 wenn keine Aenderung noetig,
-// sonst den neuen Sperrzustand
-int db_set_resolution(int issueid, int resolved, string note)
-{
- int** rows = sl_exec("SELECT resolved FROM issues WHERE id=?1;",
- issueid);
- if (!rows)
- return -1; // nicht vorhanden.
-
- if (resolved && !rows[0][0])
- {
- // Als gefixt markieren.
-// sl_exec("BEGIN TRANSACTION;");
- sl_exec("UPDATE issues SET resolved=1,resolver=?2,mtime=?3 "
- "WHERE id=?1;",
- issueid, getuid(TI),time());
- db_add_note( (<note_s> id: issueid, time: time(), user: getuid(TI),
- txt: sprintf("Fehler gefixt: %s",
- note ? note : "<kein Kommentar>")) );
-// sl_exec("COMMIT;");
- return 1;
- }
- else if (!resolved && rows[0][0])
- {
- // als nicht gefixt markieren.
-// sl_exec("BEGIN TRANSACTION;");
- sl_exec("UPDATE issues SET resolved=0,resolver=0,mtime=?2 "
- "WHERE id=?1;", issueid, time());
- db_add_note( (<note_s> id: issueid, time: time(), user: getuid(TI),
- txt: sprintf("Fix zurueckgezogen: %s",
- note ? note : "<kein Kommentar>")) );
-// sl_exec("COMMIT;");
- return 0;
- }
- // nix aendern.
- return -3;
-
-}
-
-// Transferiert ein Issue zu einer neuen zustaendigen UID
-// Prueft, ob <issueid> existiert und aendert den Zustand nur, wenn noetig.
-// Rueckgabe: -1, wenn Issue nicht existiert, -3 wenn keine Aenderung noetig,
-// 1, wenn erfolgreich neu zugewiesen
-int db_reassign_issue(int issueid, string newuid, string note)
-{
- string** rows = sl_exec("SELECT uid FROM issues WHERE id=?1;",
- issueid);
- if (!rows)
- return -1; // nicht vorhanden.
-
- if (!stringp(newuid))
- return(-2);
-
- if (newuid != rows[0][0])
- {
-// sl_exec("BEGIN TRANSACTION;");
- sl_exec("UPDATE issues SET uid=?2,mtime=?3 WHERE id=?1;",
- issueid, newuid,time());
- db_add_note( (<note_s> id: issueid, time: time(), user: getuid(TI),
- txt: sprintf("Fehler von %s an %s uebertragen. (%s)",
- rows[0][0], newuid,
- note ? note : "<kein Kommentar>")) );
-// sl_exec("COMMIT;");
- return 1;
- }
-
- return -3;
-}
-
-// inkrementiert count und aktualisiert mtime, atime.
-// Ausserdem wird ggf. das Loeschflag genullt - ein erneut aufgetretener
-// Fehler sollte anschliessend nicht mehr geloescht sein. Geloeste
-// (resolved) Eintraege werden NICHT auf ungeloest gesetzt. Vermutlich trat
-// der Fehler in einem alten Objekte auf...
-// Issue muss in der DB existieren.
-int db_countup_issue(int issueid)
-{
- sl_exec("UPDATE issues SET count=count+1,mtime=?2,atime=?2,deleted=0 WHERE id=?1;",
- issueid,time());
- return 1;
-}
-
-// Das Issue wird ggf. ent-loescht und als nicht resvolved markiert.
-// Sind pl und msg != 0, wird eine Notiz angehaengt.
-// aktualisiert mtime, atime.
-// Issue muss in der DB existieren.
-int db_reopen_issue(int issueid, string pl, string msg)
-{
- int** row=sl_exec("SELECT deleted,resolved from issues WHERE id=?1;",
- issueid);
- if (pointerp(row)
- && (row[0][0] || row[0][1]) )
- {
-// sl_exec("BEGIN TRANSACTION;");
- if (pl && msg)
- {
- db_add_note( (<note_s> id: issueid,
- time: time(),
- user: pl,
- txt: msg) );
- }
- sl_exec("UPDATE issues SET "
- "deleted=0,resolved=0,resolver=0,mtime=?2,atime=?2 WHERE id=?1;",
- issueid,time());
-// sl_exec("COMMIT;");
- }
- return 1;
-}
-
-int db_insert_issue(struct fullissue_s issue)
-{
- //DEBUG(sprintf("db_insert: %O\n", issue));
-
- mixed row=sl_exec("SELECT id from issues WHERE hashkey=?1;",
- issue->hashkey);
- //DEBUG(sprintf("insert: %s: %O\n",issue->hashkey,row));
- if (pointerp(row))
- {
- issue->id=row[0][0];
- return db_countup_issue(issue->id);
- }
-// sl_exec("BEGIN TRANSACTION;");
- sl_exec("INSERT INTO issues(hashkey,uid,type,mtime,ctime,atime,count,"
- "deleted,resolved,locked,locked_by,locked_time,resolver,message,"
- "loadname,obj,prog,loc,titp,tienv,hbobj,caught,command,verb) "
- "VALUES(?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14,?15,"
- "?16,?17,?18,?19,?20,?21,?22,?23,?24);",
- (to_array(issue)[1..24])...);
- issue->id=sl_insert_id();
-
- if (pointerp(issue->stack))
- {
- foreach(struct frame_s entry : issue->stack)
- {
- entry->id = issue->id;
- sl_exec("INSERT INTO stacktraces(issueid,type,name,prog,obj,loc,ticks) "
- "VALUES(?1,?2,?3,?4,?5,?6,?7);",
- to_array(entry)...);
- }
- }
- if (pointerp(issue->notes))
- {
- foreach(struct note_s entry : issue->notes)
- {
- entry->id = issue->id;
- sl_exec("INSERT INTO notes(issueid,time,user,txt) "
- "VALUES(?1,?2,?3,?4);",
- to_array(entry)...);
- }
- }
-// sl_exec("COMMIT;");
-
- return issue->id;
-}
-
-
-// loggt einen T_REPORTED_ERR, T_REPORTED_IDEA, T_REPORTED_TYPO,
-// T_REPORTED_MD, T_REPORTED_SYNTAX
-public string LogReportedError(mapping err)
-{
- //darf nur von Spielershells oder Objekt in /obj/ (z.B. Fehlerteufel oder
- //vitem_proxy) gerufen werden.
- if (extern_call() && !previous_object()
- || (strstr(load_name(previous_object()),"/std/shells/") == -1
- && strstr(load_name(previous_object()), "/"LIBOBJDIR"/") == -1))
- return 0;
-
- //DEBUG("LogReportedError\n");
- // DEBUG(sprintf("%O\n",err));
- string uid = ({string})master()->creator_file(err[F_OBJ]);
-
- // default-Typ
- if (!member(err, F_TYPE)) err[F_TYPE] = T_REPORTED_ERR;
-
- // div. Keys duerfen nicht gesetzt sein.
- err -= ([F_STATE, F_READSTAMP, F_CAUGHT, F_STACK, F_CLI, F_VERB,
- F_LOCK, F_RESOLVER, F_NOTES]);
-
- // Errormapping in issue-struct umwandeln und befuellen.
- struct fullissue_s issue = (<fullissue_s>);
- issue->type = err[F_TYPE];
- issue->uid = uid;
- issue->mtime = issue->ctime = issue->atime = time();
- issue->count=1;
- issue->loadname = load_name(err[F_OBJ]);
- issue->message = err[F_MSG];
- issue->obj = objectp(err[F_OBJ]) ? object_name(err[F_OBJ]) : err[F_OBJ];
- issue->loc = err[F_LINE];
- // Normalisieren auf fuehrenden / und kein .c
-<<<<<<< HEAD
- if (err[F_PROG]!="unbekannt")
- issue->prog=err[F_PROG][0] in "/#<" ? err[F_PROG] : "/" + err[F_PROG];
- else
- issue->prog = "unbekannt";
-=======
- if (stringp(err[F_PROG]))
- issue->prog = load_name(err[F_PROG]);
->>>>>>> a811db8d (Fehlendes Programm als 0 speichern)
- issue->titp = getuid(this_interactive() || this_player());
- issue->tienv = object_name(environment(this_interactive() || this_player()));
-
- //DEBUG(sprintf("%O\n",issue));
- issue->hashkey = hash(TLS_HASH_MD5,
- sprintf("%d%s%s", issue->type, issue->loadname, issue->message));
-
- // ggf. vorhandenen Fehler suchen - zugegeben: sollte bei von Spielern
- // gemeldeten Dingen vermutlich nie vorkommen...
- int oldid = getErrorID(issue->hashkey);
- if (oldid >= 0)
- {
- // ggf. sicherstellen, dass er wieder eroeffnet wird.
- db_reopen_issue(oldid, "<ErrorD>",
- "Automatisch wiedereroeffnet wegen erneutem Auftreten.");
- db_countup_issue(oldid);
- return issue->hashkey;
- }
-
- // sonst fuegen wir einen neuen Eintrag hinzu
- // Spielergemeldete Bugs werden erstmal vor automatischem Loeschen
- // geschuetzt, bis ein zustaendiger Magier ihn zur Kenntnis nimmt und
- // entsperrt.
- issue->locked = 1;
- issue->locked_by = getuid(TI || PL);
- issue->locked_time = time();
-
- // In DB eintragen.
- issue->id = db_insert_issue(issue);
-
- lasterror[issue->type]=issue->id;
-
- // Event triggern, aber nur eine Teilmenge der Daten direkt mitliefern.
- EVENTD->TriggerEvent(EVT_LIB_NEW_ERROR,
- ([F_TYPE: issue->type, F_HASHKEY:issue->hashkey,
- F_UID:issue->uid, F_ID: issue->id]));
-
- DEBUG(sprintf("LogReportedError: %s\n",issue->hashkey));
-
- return issue->hashkey;
-}
-
-//Fehler registrieren
-//Diese Funktion darf nicht mehr als 200k Ticks verbrauchen und wird nur vom
-//Master gerufen!
-public int LogError(string msg,string prg,string curobj,int line,mixed culprit,
- int caught)
-{
- //DEBUG(sprintf("LogError: Prog: %O, Obj: %O,\n",prg,curobj));
-
- //darf nur vom Master gerufen werden
- if (!extern_call() ||
- (previous_object() && previous_object() != master()))
- return 0;
-
- struct fullissue_s issue = (<fullissue_s>);
-
- //UID bestimmen, curobj is 0 for lwobjects, then the program is used.
- issue->uid=({string})master()->creator_file(curobj || prg);
- //DEBUG(sprintf("LogError: UID: %s\n",issue->uid));
-
- //Loadname (besser als BP, falls rename_object() benutzt wurde) bestimmen
- if (!stringp(curobj) || !sizeof(curobj))
- issue->loadname = curobj = "<Unbekannt>";
- else
- {
- //load_name nimmt Strings und Objects und konstruiert den loadname,
- //wie er sein sollte, wenn das Objekt nicht mehr existiert.
- issue->loadname=load_name(curobj);
- }
- if (!stringp(issue->loadname))
- {
- //hier kommt man rein, falls curobj ein 'kaputter' Name ist,
- //d.h. load_name() 0 liefert.
- issue->loadname="<Illegal object name>";
- }
-
- // Wenn curobj in /players/ liegt, es einen TI gibt, welcher ein Magier
- // ist und dieser die Prop P_DONT_LOG_ERRORS gesetzt hat, wird der FEhler
- // nicht gespeichert.
- if (this_interactive() && IS_LEARNER(this_interactive())
- && strstr(issue->loadname,WIZARDDIR)==0
- && ({int})this_interactive()->QueryProp(P_DONT_LOG_ERRORS))
- {
- return 0;
- }
-
- // prg und curobj auf fuehrenden / und ohne .c am Ende normieren.
- if (stringp(prg))
- issue->prog=prg[0] in "/#<" ? prg : "/" + prg;
- if (stringp(curobj) && curobj[0]!='/')
- {
- curobj="/"+curobj;
- }
-
- issue->obj = curobj;
- issue->loc = line;
- issue->message = msg;
- issue->ctime = issue->mtime = issue->atime = time();
- issue->type = T_RTERROR;
- issue->count = 1;
- issue->caught = caught;
-
- //Hashkey bestimmen: Typ, Name der Blueprint des buggenden Objekts,
- //Programmname, Zeilennr., Fehlermeldung
- //TODO: evtl. sha1() statt md5()?
- issue->hashkey=hash(TLS_HASH_MD5,
- sprintf("%d%s%s%d%s", T_RTERROR, issue->loadname||"",
- issue->prog || "", issue->loc,
- issue->message||"<No error message given.>"));
- DEBUG(sprintf("LogError: Hashkey: %s", issue->hashkey));
-
- // ggf. vorhandenen Fehler suchen
- int oldid = getErrorID(issue->hashkey);
- if (oldid >= 0)
- {
- db_reopen_issue(oldid, "<ErrorD>",
- "Automatisch wiedereroeffnet wegen erneutem Auftreten.");
- db_countup_issue(oldid);
- return oldid;
- }
-
- //sonst fuegen wir einen neuen Eintrag hinzu
- //DEBUG(sprintf("LogError: OBJ: %s, BP: %s",curobj,loadname));
- // Wenn Fehler im HB, Objektnamen ermitteln
- if (objectp(culprit))
- issue->hbobj = object_name(culprit);
-
- //gibt es einen TI/TP? Name mit erfassen
- mixed tienv;
- if(objectp(this_interactive()))
- {
- issue->titp=getuid(this_interactive());
- tienv=environment(this_interactive());
- }
- else if (objectp(PL) && query_once_interactive(PL))
- {
- issue->titp=getuid(PL);
- tienv=environment(PL);
- }
- else if (objectp(PL))
- {
- issue->titp=object_name(PL);
- tienv=environment(PL);
- }
- if (objectp(tienv))
- issue->tienv=object_name(tienv);
-
- // Mal schauen, ob der Commandstack auch was fuer uns hat. ;-)
- mixed cli;
- if (pointerp(cli=command_stack()) && sizeof(cli))
- {
- issue->verb=cli[0][CMD_VERB];
- issue->command=cli[0][CMD_TEXT];
- }
-
- //stacktrace holen
- mixed stacktrace;
- if (caught)
- stacktrace=debug_info(DINFO_TRACE,DIT_ERROR);
- else
- stacktrace=debug_info(DINFO_TRACE,DIT_UNCAUGHT_ERROR);
- // gueltige Stacktraces haben min. 2 Elemente.
- // (leerer Trace: ({"No trace."}))
- if (sizeof(stacktrace) > 1)
- {
- int i;
- issue->stack = allocate(sizeof(stacktrace)-1);
- // erstes Element ist 0 oder HB-Objekt: kein frame, daher ueberspringen
- foreach(mixed entry : stacktrace[1..])
- {
- // frame->id will be set later by db_insert_issue().
- struct frame_s frame = (<frame_s> type : entry[TRACE_TYPE],
- name: entry[TRACE_NAME],
- prog: entry[TRACE_PROGRAM],
- obj: entry[TRACE_OBJECT],
- loc: entry[TRACE_LOC],
- ticks: entry[TRACE_EVALCOST]);
- issue->stack[i] = frame;
- ++i;
- }
- }
-
- issue->id = db_insert_issue(issue);
-
- lasterror[T_RTERROR]=issue->id;
-
- // Event triggern, aber nur eine Teilmenge der Daten direkt mitliefern.
- EVENTD->TriggerEvent(EVT_LIB_NEW_ERROR,
- ([ F_TYPE: T_RTERROR, F_HASHKEY: issue->hashkey, F_UID:
- issue->uid, F_ID: issue->id ]));
-
-// DEBUG(sprintf("LogError: Fehlereintrag:\n%O\n",
-// errors[uid][hashkey]));
-// DEBUG(sprintf("LogError: Verbrauchte Ticks: %d\n",
-// 200000-get_eval_cost()));
- return issue->id;
-}
-
-//Warnungen registrieren
-//Diese Funktion darf nicht mehr als 200k Ticks verbrauchen und wird nur vom
-//Master gerufen!
-public int LogWarning(string msg,string prg,string curobj,int line, int in_catch)
-{
- //DEBUG(sprintf("LogWarning: Prog: %O, Obj: %O,\n",prg,curobj));
-
- //darf nur vom Master gerufen werden
- if (!extern_call() ||
- (previous_object() && previous_object() != master()))
- return 0;
-
- struct fullissue_s issue = (<fullissue_s>);
-
- //UID bestimmen, curobj is 0 for lwobjects, then the program is used.
- issue->uid=({string})master()->creator_file(curobj || prg);
- //DEBUG(sprintf("LogWarning UID: %s\n",uid));
-
- //Loadname (besser als BP, falls rename_object() benutzt wurde) bestimmen
- if (!stringp(curobj) || !sizeof(curobj))
- issue->loadname = curobj = "<Unbekannt>";
- else
- {
- //load_name nimmt Strings und Objects und konstruiert den loadname,
- //wie er sein sollte, wenn das Objekt nicht mehr existiert.
- issue->loadname=load_name(curobj);
- }
-
- if (!stringp(issue->loadname))
- //hier sollte man reinkommen, falls curobj ein 'kaputter' Name ist,
- //d.h. load_name() 0 liefert.
- issue->loadname="<Illegal object name>";
-
- // prg und curobj auf abs. Pfade normalisieren. Dabei Spezialfaelle
- // beruecksichtigen, z.B. dass prg "#'call_out" sein kann.
- if (stringp(prg))
- issue->prog=prg[0] in "/#<" ? prg : "/" + prg;
- if (stringp(curobj) && curobj[0]!='/')
- {
- curobj="/"+curobj;
- }
-
- //DEBUG(sprintf("LogWarning: OBJ: %s, BP: %s\n",curobj,blue));
-
- // Wenn curobj in /players/ liegt, es einen TI gibt, welcher ein Magier
- // ist und dieser die Prop P_DONT_LOG_ERRORS gesetzt hat, wird der FEhler
- // nicht gespeichert.
- if (this_interactive() && IS_LEARNER(this_interactive())
- && strstr(issue->loadname,WIZARDDIR)==0
- && ({int})this_interactive()->QueryProp(P_DONT_LOG_ERRORS)) {
- return 0;
- }
-
- //Hashkey bestimmen, Typ, Name der Blueprint des buggenden Objekts, Programm
- //Zeilennr., Warnungsmeldung
- issue->hashkey=hash(TLS_HASH_MD5,
- sprintf("%d%s%s%d%s", T_RTWARN, issue->loadname,
- issue->prog||"", line, msg));
- //DEBUG(sprintf("LogWarning: Hashkey: %s",hashkey));
-
-
- // ggf. vorhandenen Fehler suchen
- int oldid = getErrorID(issue->hashkey);
- if (oldid >= 0)
- {
- db_reopen_issue(oldid, "<ErrorD>",
- "Automatisch wiedereroeffnet wegen erneutem Auftreten.");
- db_countup_issue(oldid);
- return oldid;
- }
-
- //sonst fuegen wir einen neuen Eintrag hinzu
- // erstmal vervollstaendigen
- issue->obj = curobj;
- issue->message = msg;
- issue->ctime = issue->mtime = issue->atime = time();
- issue->loc = line;
- issue->count = 1;
- issue->type = T_RTWARN;
- issue->caught = in_catch;
-
- //gibt es einen TI/TP? Name mit erfassen
- mixed tienv;
- if(objectp(this_interactive()))
- {
- issue->titp=getuid(this_interactive());
- tienv=environment(this_interactive());
- }
- else if (objectp(PL) && query_once_interactive(PL))
- {
- issue->titp=getuid(PL);
- tienv=environment(PL);
- }
- else if (objectp(PL))
- {
- issue->titp=object_name(PL);
- tienv=environment(PL);
- }
- if (objectp(tienv))
- issue->tienv=object_name(tienv);
-
- // Mal schauen, ob der Commandstack auch was fuer uns hat. ;-)
- mixed cli;
- if (pointerp(cli=command_stack()) && sizeof(cli))
- {
- issue->verb=cli[0][CMD_VERB];
- issue->command=cli[0][CMD_TEXT];
- }
-
- issue->id = db_insert_issue(issue);
-
- lasterror[T_RTWARN]=issue->id;
- // Event triggern, aber nur eine Teilmenge der Daten direkt mitliefern.
- EVENTD->TriggerEvent(EVT_LIB_NEW_ERROR,
- ([F_TYPE: issue->type, F_ID: issue->id,
- F_UID: issue->uid, F_HASHKEY: issue->hashkey]) );
-
-// DEBUG(sprintf("LogWarning: Warnungseintrag:\n%O\n",
-// warnings[uid][hashkey]));
-// DEBUG(sprintf("LogWarning: Verbrauchte Ticks: %d\n",
-// 200000-get_eval_cost()));
- return issue->id;
-}
-
-//Warnungen und Fehler beim Kompilieren registrieren
-//Diese Funktion darf nicht mehr als 200k Ticks verbrauchen und wird nur vom
-//Master gerufen!
-public int LogCompileProblem(string file,string msg,int warn) {
-
- //DEBUG(sprintf("LogCompileProblem: Prog: %O, Obj: %O,\n",file,msg));
-
- //darf nur vom Master gerufen werden
- if (!extern_call() ||
- (previous_object() && previous_object() != master()))
- return 0;
-
- struct fullissue_s issue = (<fullissue_s>);
-
- //UID bestimmen
- issue->uid=({string})master()->creator_file(file);
- //DEBUG(sprintf("LogCompileProblem UID: %s\n",uid));
-
- // An File a) fuehrenden / anhaengen und b) endendes .c abschneiden. Macht
- // beides netterweise load_name().
- issue->loadname = load_name(file);
- issue->type = warn ? T_CTWARN : T_CTERROR;
-
- //loggen wir fuer das File ueberhaupt?
- if (member(BLACKLIST,explode(issue->loadname,"/")[<1])>=0)
- return 0;
-
- //Hashkey bestimmen, in diesem Fall einfach, wir koennen die
- //Fehlermeldunge selber nehmen.
- issue->hashkey=hash(TLS_HASH_MD5,sprintf(
- "%d%s%s",issue->type,issue->loadname, msg));
- //DEBUG(sprintf("LogCompileProblem: Hashkey: %s",hashkey));
-
- // ggf. vorhandenen Fehler suchen
- int oldid = getErrorID(issue->hashkey);
- if (oldid >= 0)
- {
- db_reopen_issue(oldid, "<ErrorD>",
- "Automatisch wiedereroeffnet wegen erneutem Auftreten.");
- db_countup_issue(oldid);
- return oldid;
- }
-
- // neuen Eintrag
- issue->message = msg;
- issue->count = 1;
- issue->ctime = issue->mtime = issue->atime = time();
-
- issue->id = db_insert_issue(issue);
-
- if (warn) lasterror[T_CTWARN]=issue->id;
- else lasterror[T_CTERROR]=issue->id;
-
-// DEBUG(sprintf("LogCompileProblem: Eintrag:\n%O\n",
-// (warn ? ctwarnings[uid][hashkey] : cterrors[uid][hashkey])));
-// DEBUG(sprintf("LogCompileProblem: Verbrauchte Ticks: %d\n",
-// 200000-get_eval_cost()));
- return issue->id;
-}
-
-/* **************** Public Interface ****************** */
-
-//Einen bestimmten Fehler nach Hashkey suchen und als fullissue_s inkl. Notes
-//und Stacktrace liefern.
-struct fullissue_s QueryIssueByHash(string hashkey)
-{
- struct fullissue_s issue = db_get_issue(0, hashkey);
- if (structp(issue))
- return filter_private(issue);
- return 0;
-}
-//Einen bestimmten Fehler nach ID suchen und als fullissue_s inkl. Notes
-//und Stacktrace liefern.
-struct fullissue_s QueryIssueByID(int issueid)
-{
- struct fullissue_s issue = db_get_issue(issueid, 0);
- if (structp(issue))
- return filter_private(issue);
- return 0;
-}
-
-// den letzten Eintrag den jeweiligen Typ liefern.
-struct fullissue_s QueryLastIssue(int type)
-{
- if (!member(lasterror,type))
- return 0;
- //einfach den kompletten letzten Eintrag zurueckliefern
- return(QueryIssueByID(lasterror[type]));
-}
-
-// Liefert alle Issues, deren obj,prog oder loadname gleich <file> ist.
-public struct fullissue_s* QueryIssuesByFile(string file, int type)
-{
- mixed rows = sl_exec("SELECT * FROM issues "
- "WHERE (loadname=?1 OR prog=?1 OR obj=?1) "
- "AND deleted=0 AND resolved=0 AND type=?2"
- "ORDER BY type,mtime;", file, type);
- if (pointerp(rows))
- {
- struct fullissue_s* ilist = allocate(sizeof(rows));
- int i;
- foreach(mixed row : rows)
- {
- // Einfachster Weg - funktioniert aber nur, solange die Felder in der DB
- // die gleiche Reihenfolge wie in der struct haben! Entweder immer
- // sicherstellen oder Ergebnisreihenfolge oben im select festlegen!
- struct fullissue_s issue = to_struct( row, (<fullissue_s>) );
- if (issue->type == T_RTERROR)
- issue->stack = db_get_stack(issue->id);
- issue->notes = db_get_notes(issue->id);
- ilist[i] = filter_private(issue);
- ++i;
- }
- return ilist;
- }
- return 0;
-}
-
-// Liefert eine Liste von allen IDs, Loadnames, UIDs und Typen fuer die
-// angebenen <type> und <uid>.
-varargs < <int|string>* >* QueryIssueListByFile(string file)
-{
- mixed rows = sl_exec("SELECT id,loadname,obj,prog,loc FROM issues "
- "WHERE (loadname=?1 OR prog=?1 OR obj=?1) "
- "AND deleted=0 AND resolved=0 "
- "ORDER BY type,mtime;", file);
- return rows;
-}
-
-// Liefert eine Liste von allen IDs, Loadnames, UIDs und Typen fuer die
-// angebenen <type> und <uid>.
-varargs < <int|string>* >* QueryIssueListByLoadname(string file, int type)
-{
- mixed rows;
- if (type && file)
- {
- rows = sl_exec("SELECT id,loadname,uid,type FROM issues "
- "WHERE loadname=?1 AND type=?2 AND deleted=0 "
- "AND resolved=0 "
- "ORDER BY type,mtime;", file, type);
- }
- else if (type)
- {
- rows = sl_exec("SELECT id,loadname,uid,type FROM issues "
- "WHERE type=?1 AND deleted=0 AND resolved=0 "
- "ORDER BY type,mtime;", type);
- }
- else if (file)
- {
- rows = sl_exec("SELECT id,loadname,uid,type FROM issues "
- "WHERE loadname=?1 AND deleted=0 AND resolved=0 "
- "ORDER BY type,mtime;", file);
- }
- return rows;
-}
-
-
-// Liefert eine Liste von allen IDs, Loadnames, UIDs und Typen fuer die
-// angebenen <type> und <uid>.
-varargs < <int|string>* >* QueryIssueList(int type, string uid)
-{
- mixed rows;
- if (type && uid)
- {
- rows = sl_exec("SELECT id,loadname,uid,type FROM issues "
- "WHERE type=?1 AND uid=?2 AND deleted=0 "
- "AND resolved=0 "
- "ORDER BY type,rowid;", type,uid);
- }
- else if (type)
- {
- rows = sl_exec("SELECT id,loadname,uid,type FROM issues "
- "WHERE type=?1 AND deleted=0 AND resolved=0 "
- "ORDER BY type,rowid;", type);
- }
- else if (uid)
- {
- rows = sl_exec("SELECT id,loadname,uid,type FROM issues "
- "WHERE uid=?1 AND deleted=0 AND resolved=0 "
- "ORDER BY type,rowid;", uid);
- }
- return rows;
-}
-
-varargs string* QueryUIDsForType(int type) {
- //liefert alle UIDs fuer einen Fehlertyp oder fuer alle Fehlertypen
- string** rows;
-
- if (type)
- {
- rows = sl_exec("SELECT uid FROM issues "
- "WHERE type=?1 AND deleted=0 AND resvoled=0;", type);
- }
- else
- rows = sl_exec("SELECT uid FROM issues WHERE deleted=0 "
- "AND resolved=0;");
-
- return map(rows, function string (string* item)
- {return item[0];} );
-}
-
-//Wieviele unterschiedliche Fehler in diesem Typ?
-varargs int QueryUniqueIssueCount(int type, string uid)
-{
- int** rows;
-
- if (type && uid)
- {
- rows = sl_exec("SELECT count(*) FROM issues "
- "WHERE type=?1 AND uid=?2 AND deleted=0 AND resolved=0;",
- type, uid);
- }
- else if (type)
- {
- rows = sl_exec("SELECT count(*) FROM issues "
- "WHERE type=?1 AND deleted=0 AND resolved=0;",
- type);
- }
- else if (uid)
- {
- rows = sl_exec("SELECT count(*) FROM issues "
- "WHERE uid=?1 AND deleted=0 AND resolved=0;",
- uid);
- }
- else
- rows = sl_exec("SELECT count(*) FROM issues "
- "WHERE deleted=0 AND resolved=0;");
-
- return rows[0][0];
-}
-
-//Einen bestimmten Fehler loeschen
-varargs int ToggleDeleteError(int issueid, string note)
-{
- mixed rows = sl_exec("SELECT uid,deleted from issues WHERE id=?1;",
- issueid);
- if (!pointerp(rows))
- return -1;
-
- if (!access_check(rows[0][0], M_DELETE))
- //zugriff zum Schreiben nicht gestattet
- return -10;
-
-// sl_exec("BEGIN TRANSACTION;");
- if (rows[0][1])
- {
- // was deleted -> undelete it
- sl_exec("UPDATE issues SET deleted=0,mtime=?2 WHERE id=?1;",
- issueid,time());
- db_add_note((<note_s> id: issueid, time: time(), user: getuid(TI),
- txt: sprintf("Loeschmarkierung entfernt. (%s)",
- note ? note: "<kein Kommentar>")
- ));
- }
- else
- {
- // was not deleted -> delete it.
- sl_exec("UPDATE issues SET deleted=1,mtime=?2 WHERE id=?1;",
- issueid, time());
- db_add_note((<note_s> id: issueid, time: time(), user: getuid(TI),
- txt: sprintf("Loeschmarkierung gesetzt. (%s)",
- note ? note: "<kein Kommentar>")
- ));
- }
-// sl_exec("COMMIT;");
- return !rows[0][1];
-}
-
-
-// sperrt den Eintrag oder entsperrt ihn.
-// Sperre heisst hier, dass der Fehler vom Expire nicht automatisch geloescht
-// wird.
-varargs int LockIssue(int issueid, string note) {
- return set_lock(issueid, 1, note);
-}
-
-varargs int UnlockIssue(int issueid, string note) {
- return set_lock(issueid, 0, note);
-}
-
-// einen Fehler als gefixt markieren
-varargs int ResolveIssue(int issueid, string note) {
- return set_resolution(issueid, 1, note);
-}
-// einen Fehler als nicht gefixt markieren
-varargs int ReOpenIssue(int issueid, string note) {
- return set_resolution(issueid, 0, note);
-}
-
-varargs int AddNote(int issueid, string note)
-{
-
- if (!stringp(note) || !sizeof(note))
- return(-3);
-
- // existiert die ID in der DB?
- struct fullissue_s issue = db_get_issue(issueid,0);
- if (!issue)
- return -1;
-
- if (!access_check(issue->uid, M_WRITE))
- //zugriff zum Schreiben nicht gestattet
- return(-10);
-
- return db_add_note((<note_s> id: issueid, time: time(), user: getuid(TI),
- txt: note));
-}
-
-//Einen bestimmten Fehler einer anderen UID zuweisen.
-//Hashkey ist zwar eindeutig, aber Angabe der
-//der UID ist deutlich schneller. Weglassen des Typs nochmal langsamer. ;-)
-//Potentiell also sehr teuer, wenn man UID oder UID+Typ weglaesst.
-varargs int ReassignIssue(int issueid, string newuid, string note)
-{
- struct fullissue_s issue = db_get_issue(issueid,0);
- if (!issue)
- return -1;
-
- if (!access_check(issue->uid, M_REASSIGN))
- //zugriff zum Schreiben nicht gestattet
- return(-10);
-
- return db_reassign_issue(issueid, newuid, note);
-}
-
-varargs int ChangeType(int issueid, int newtype, int oldtype, string note)
-{
- struct fullissue_s issue = db_get_issue(issueid, 0);
- if(!issue)
- return -1;
-
- if (!access_check(issue->uid, M_CHANGE_TYPE))
- {
- // Zugriff zum Schreiben nicht gestattet
- return(-10);
- }
-
- sl_exec(
- "UPDATE issues SET type=?1,mtime=?2 WHERE id=?3;",
- newtype, time(), issueid);
- db_add_note(
- (<note_s> id: issueid, time: time(), user: getuid(TI),
- txt: sprintf("Fehlertyp von %s auf %s geaendert. (%s)",
- print_type(oldtype)[0], print_type(newtype)[0], (note || "<kein Kommentar>"))));
- return 1;
-}
-
-/* *********** Eher fuer Debug-Zwecke *********************** */
-/*
-mixed QueryAll(int type) {
- //das koennte ein sehr sehr grosses Mapping sein, ausserdem wird keine
- //Kopie zurueckgegeben, daher erstmal nur ich...
- if (!this_interactive() ||
- member(MAINTAINER,getuid(this_interactive()))<0)
- return(-1);
- if (process_call()) return(-2);
- if (!type) return(-3);
- return(errors[type]);
-}
-
-mixed QueryResolved()
-{
- //das koennte ein sehr sehr grosses Mapping sein, ausserdem wird keine
- //Kopie zurueckgegeben, daher erstmal nur ich...
- if (!this_interactive() ||
- member(MAINTAINER,getuid(this_interactive()))<0)
- return(-1);
- if (process_call()) return(-2);
- return(resolved);
-}
-*/
-
-/* ***************** Internal Stuff ******************** */
-void create() {
- seteuid(getuid(ME));
-
- if (sl_open("/"LIBDATADIR"/secure/ARCH/errord.sqlite") != 1)
- //if (sl_open("/errord.sqlite") != 1)
- {
- raise_error("Datenbank konnte nicht geoeffnet werden.\n");
- }
- sl_exec("PRAGMA foreign_keys = ON; PRAGMA temp_store = 2; ");
- //string* res=sl_exec("PRAGMA quick_check(N);");
- //if (pointerp(res))
- //{
- // raise_error("");
- //}
- //sl_exec("CREATE TABLE issue(id INTEGER,haskey TEXT);");
- foreach (string cmd :
- explode(read_file("/secure/ARCH/errord.sql.init"),";\n"))
- {
- if (sizeof(cmd) && cmd != "\n")
- {
- sl_exec(cmd);
- }
- }
- sl_exec("ANALYZE main;");
-
- lasterror=([]);
-}
-
-string name() {return("<Error-Daemon>");}
-
-void save_me(int now) {
- if (now)
- save_object(SAVEFILE);
- else if (find_call_out(#'save_object)==-1) {
- call_out(#'save_object, 30, SAVEFILE);
- }
-}
-
-varargs int remove(int silent) {
- save_me(1);
- destruct(ME);
- return(1);
-}
-
-
-// sperrt den Eintrag (lock!=0) oder entsperrt ihn (lock==0).
-// Sperre heisst hier, dass der Fehler vom Expire nicht automatisch geloescht
-// wird.
-// liefert <0 im Fehlerfall, sonst Array mit Lockdaten
-private varargs int set_lock(int issueid, int lock, string note)
-{
- struct fullissue_s issue = db_get_issue(issueid,0);
- if (!issue)
- return -1;
-
- if (!access_check(issue->uid, M_WRITE))
- //zugriff zum Schreiben nicht gestattet
- return(-10);
-
- return db_set_lock(issueid, lock, note);
-}
-
-//markiert einen Fehler als gefixt, mit 'note' als Bemerkung (res!=0) oder
-//markiert einen Fehler wieder als nicht-gefixt (resolution==0)
-//liefert < 0 im Fehlerfall, sonst den neuen Zustand.
-private varargs int set_resolution(int issueid, int resolution, string note)
-{
- struct fullissue_s issue = db_get_issue(issueid,0);
- if (!issue)
- return -1;
-
- // Fixen duerfen nur zustaendige
- if (resolution
- && !access_check(issue->uid, M_FIX))
- return -10;
- // ggf. Fix zurueckziehen darf jeder mit M_WRITE
- if (!resolution &&
- !access_check(issue->uid, M_WRITE))
- return -10;
-
- int res = db_set_resolution(issueid, resolution, note);
-
- if (res == 1)
- {
- // Fehler jetzt gefixt.
- versende_mail(db_get_issue(issueid,0)); // per Mail verschicken
- }
-
- return res;
-}
-
-//ist der Zugriff auf uid erlaubt? Geprueft wird TI (wenn kein TI, auch kein
-//Schreibzugriff)
-//mode gibt an, ob lesend oder schreibend
-private int access_check(string uid, int mode) {
-
- if (mode==M_READ)
- return LEARNER_SECURITY; //lesen darf jeder Magier
-
- // In process_string() schonmal gar nicht.
- if (process_call()) return(0);
- // EM+ duerfen alles loeschen.
- if (ARCH_SECURITY) return(1);
- // eigene UIDs darf man auch vollumfaenglich bearbeiten.
- if (secure_euid()==uid) return(1);
-
- // alles andere wird speziell geprueft
- switch(mode)
- {
- // M_WRITE ist zur zeit eigentlich immer nen Append - das duerfen zur
- // Zeit alle ab Vollmagier
- case M_WRITE:
- return LEARNER_SECURITY;
- // Loeschen und Fixen duerfen zur Zeit nur Zustaendige.
- case M_DELETE:
- case M_REASSIGN:
- case M_FIX:
- case M_CHANGE_TYPE:
- // Master nach UIDs fragen, fuer die der jew. Magier
- // zustaendig ist.
- if (member(({string*})master()->QueryUIDsForWizard(secure_euid()),uid) >= 0)
- return 1;
-
- break;
- }
-
- return(0); //Fall-through, neinRNER_SECURITY
-}
-
-public string format_stacktrace(struct frame_s* stacktrace) {
- string *lines;
-
- if (!pointerp(stacktrace) || !sizeof(stacktrace))
- return("");
-
- lines=allocate(sizeof(stacktrace));
- int i;
- foreach(struct frame_s frame: stacktrace)
- {
- lines[i]=sprintf("Fun: %.20O in Prog: %.40s\n"
- " Zeile: %.8d [%.50s]\n"
- " Evalcosts: %d",
- frame->name,frame->prog,
- frame->loc,frame->obj,frame->ticks);
- ++i;
- }
- return(implode(lines,"\n"));
-}
-
-public string format_notes(struct note_s* notes)
-{
- int i;
- string text="";
- foreach(struct note_s note: notes)
- {
- text+=sprintf("Notiz %d von %.10s am %.30s\n%s",
- ++i,capitalize(note->user),dtime(note->time),
- break_string(note->txt, 78," "));
- }
- return text;
-}
-
-public string format_error_spieler(struct fullissue_s issue)
-{
- string txt;
- string *label;
-
- if (!issue)
- return 0;
-
- switch(issue->type)
- {
- case T_RTERROR:
- label=({"Laufzeitfehler","Dieser Laufzeitfehler"});
- break;
- case T_REPORTED_ERR:
- label=({"Fehlerhinweis","Dieser Fehlerhinweis"});
- break;
- case T_REPORTED_TYPO:
- label=({"Typo","Dieser Typo"});
- break;
- case T_REPORTED_IDEA:
- label=({"Idee","Diese Idee"});
- break;
- case T_REPORTED_MD:
- label=({"Fehlendes Detail","Dieses fehlende Detail"});
- break;
- case T_REPORTED_SYNTAX:
- label=({"Syntaxproblem","Dieses Syntaxproblem"});
- break;
- case T_RTWARN:
- label=({"Laufzeitwarnung","Diese Laufzeitwarnung"});
- break;
- case T_CTWARN:
- label=({"Ladezeitwarnung","Diese Ladezeitwarnung"});
- break;
- case T_CTERROR:
- label=({"Ladezeitfehler","Dieser Ladezeitfehler"});
- break;
- default: return 0;
- }
-
- txt=sprintf( "\nDaten fuer %s mit ID '%s':\n"
- "Zeit: %25s\n",
- label[0], issue->hashkey,
- dtime(issue->ctime)
- );
-
- txt+=sprintf("%s",break_string(issue->message,78,
- "Meldung: ",BS_INDENT_ONCE));
-
- if (pointerp(issue->notes))
- txt+="Bemerkungen:\n"+format_notes(issue->notes)+"\n";
-
- return txt;
-}
-
-public string* print_type(int type)
-{
- string* res;
- switch(type)
- {
- case T_RTERROR:
- res = ({"Laufzeitfehler","Dieser Laufzeitfehler"});
- break;
- case T_REPORTED_ERR:
- res = ({"Fehlerhinweis","Dieser Fehlerhinweis"});
- break;
- case T_REPORTED_TYPO:
- res = ({"Typo","Dieser Typo"});
- break;
- case T_REPORTED_IDEA:
- res = ({"Idee","Diese Idee"});
- break;
- case T_REPORTED_MD:
- res = ({"Fehlendes Detail","Dieses fehlende Detail"});
- break;
- case T_REPORTED_SYNTAX:
- res = ({"Syntaxproblem","Dieses Syntaxproblem"});
- break;
- case T_RTWARN:
- res = ({"Laufzeitwarnung","Diese Laufzeitwarnung"});
- break;
- case T_CTWARN:
- res = ({"Ladezeitwarnung","Diese Ladezeitwarnung"});
- break;
- case T_CTERROR:
- res = ({"Ladezeitfehler","Dieser Ladezeitfehler"});
- break;
- default:
- res = 0;
- }
- return res;
-}
-
-public string format_error(struct fullissue_s issue, int only_essential)
-{
- string txt;
- string *label;
-
- if (!issue)
- return 0;
-
- label = print_type(issue->type);
- if(!label) return 0;
-
- txt=sprintf( "\nDaten fuer %s mit ID %d:\n"
- "Hashkey: %s\n"
- "Zeit: %25s (Erstmalig: %25s)\n",
- label[0], issue->id, issue->hashkey,
- dtime(abs(issue->mtime)),dtime(issue->ctime)
- );
-
- if (stringp(issue->prog))
- txt += sprintf(
- "Programm: %.60s\n"
- "Zeile: %.60d\n",
- issue->prog, issue->loc
- );
-
- if (stringp(issue->obj))
- txt+=sprintf("Objekt: %.60s\n",
- issue->obj);
-
- txt += sprintf("Loadname: %.60s\n"
- "UID: %.60s\n",
- issue->loadname, issue->uid);
-
- txt+=sprintf("%s",break_string(issue->message,78,
- "Meldung: ",BS_INDENT_ONCE));
- if (stringp(issue->hbobj))
- txt+=sprintf(
- "HB-Obj: %.60s\n",issue->hbobj);
-
- if (stringp(issue->titp)) {
- txt+=sprintf(
- "TI/TP: %.60s\n",issue->titp);
- if (stringp(issue->tienv))
- txt+=sprintf(
- "Environm.: %.60s\n",issue->tienv);
- }
-
- if (!stringp(issue->command) ||
- !ARCH_SECURITY || process_call())
- {
- // Kommandoeingabe ist Privatsphaere und darf nicht von jedem einsehbar
- // sein.
- // in diesem Fall aber zumindest das Verb ausgeben, so vorhanden
- if (issue->verb)
- txt+=sprintf(
- "Verb: %.60s\n",issue->verb);
- }
- // !process_call() && ARCH_SECURITY erfuellt...
- else if (stringp(issue->command))
- txt+=sprintf(
- "Befehl: %.60s\n",issue->command);
-
- if (issue->caught)
- txt+=label[1]+" trat in einem 'catch()' auf.\n";
-
- if (!only_essential)
- {
- if (issue->deleted)
- txt+=label[1]+" wurde als geloescht markiert.\n";
-
- if (issue->locked)
- txt+=break_string(
- sprintf("%s wurde von %s am %s vor automatischem Loeschen "
- "geschuetzt (locked).\n",
- label[1],issue->locked_by, dtime(issue->locked_time)),78);
- if (issue->resolved)
- txt+=label[1]+" wurde als erledigt markiert.\n";
- }
-
- txt+=sprintf("%s trat bisher %d Mal auf.\n",
- label[1],issue->count);
-
- if (pointerp(issue->stack))
- txt+="Stacktrace:\n"+format_stacktrace(issue->stack)+"\n";
-
- if (pointerp(issue->notes))
- txt+="Bemerkungen:\n"+format_notes(issue->notes)+"\n";
-
- return txt;
-}
-
-// letzter Aenderung eines Spieler-/Magiersavefiles. Naeherung fuer letzten
-// Logout ohne das Savefile einzulesen und P_LAST_LOGOUT zu pruefen.
-private int recent_lastlogout(string nam, int validtime)
-{
- if (!nam || sizeof(nam)<2) return 0;
- return file_time("/"LIBSAVEDIR"/" + nam[0..0] + "/" + nam + ".o") >= validtime;
-}
-
-// Versendet Mail an zustaendigen Magier und ggf. Spieler, der den Eintrag
-// erstellt hat.
-// ACHTUNG: loescht issue->command.
-private int versende_mail(struct fullissue_s issue)
-{
- // Versendet eine mail mit dem gefixten Fehler.
- mixed *mail;
- string text, *empf;
- int res = -1;
-
- mail = allocate(9);
- mail[MSG_FROM] = "<Fehler-Daemon>";
- mail[MSG_SENDER] = getuid(TI);
- mail[MSG_BCC] = 0;
- mail[MSG_SUBJECT] = sprintf("Fehler/Warnung in %s behoben", issue->loadname);
- mail[MSG_DATE] = dtime(time());
-
- // auch wenn ein EM fixt, sollen die Empfaenger nicht automatisch die
- // Spielereingabe erhalten, also command loeschen.
- issue->command = 0;
-
- // erstmal eine Mail an zustaendige Magier.
- empf = ({string*})master()->QueryWizardsForUID(issue->uid);
- // lang (180 Tage) nicht eingeloggte Magier ausfiltern
- empf = filter(empf, #'recent_lastlogout, time() - 15552000);
- if (sizeof(empf))
- {
-
- text = break_string(
- sprintf(STANDARDMAILTEXT,capitalize(getuid(TI)))
- +format_error(issue, 1),78,"",BS_LEAVE_MY_LFS);
-
- mail[MSG_RECIPIENT] = empf[0];
- if (sizeof(empf)>1)
- mail[MSG_CC] = empf[1..];
- else
- mail[MSG_CC] = 0;
- mail[MSG_BODY]=text;
- mail[MSG_ID]=sprintf(MUDNAME": %d.%d",time(),random(__INT_MAX__));
-
- if (!sizeof(({string*})"/secure/mailer"->DeliverMail(mail,0)))
- res = -1; // an niemanden erfolgreich zugestellt. :-(
- else
- res = 1;
- }
-
- // Bei von Spielern gemeldeten Fehler werden Spieler bei
- // Erledigung informiert, wenn deren letzter Logout weniger als 180 Tage her
- // ist.
- if ( (issue->type &
- (T_REPORTED_ERR|T_REPORTED_TYPO|T_REPORTED_IDEA|T_REPORTED_MD|
- T_REPORTED_SYNTAX))
- && issue->titp
- && recent_lastlogout(issue->titp, time() - 15552000) )
- {
- text = break_string(
- sprintf(STANDARDMAILTEXT_ERRORHINT,
- capitalize(issue->titp), capitalize(getuid(TI)))
- +format_error_spieler(issue), 78,"",BS_LEAVE_MY_LFS);
-
- mail[MSG_ID]=sprintf(MUDNAME": %d.%d",time(),random(__INT_MAX__));
- mail[MSG_RECIPIENT] = issue->titp;
- mail[MSG_CC] = 0;
- mail[MSG_SUBJECT] = sprintf("Fehler/Idee/Typo wurde von %s bearbeitet",
- getuid(TI));
- mail[MSG_BODY] = text;
-
- if (!sizeof(({string*})"/secure/mailer"->DeliverMail(mail,0)))
- res |= -1;
- else
- res |= 1;
- }
-
- return res;
-}
-
-void reset()
-{
- // geloeschte Issues sofort, gefixte 30 Tage nach letzter Aenderung
- // loeschen.
- sl_exec("DELETE FROM issues WHERE deleted=1;");
- sl_exec("DELETE FROM issues WHERE resolved=1 AND mtime<?1;",
- time()-30*24*3600);
- set_next_reset(3600*24);
-}
-
-// Nicht jeder Magier muss den ErrorD direkt zerstoeren koennen.
-public string NotifyDestruct(object caller) {
- if( (caller!=this_object() && !ARCH_SECURITY) || process_call() ) {
- return "Du darfst den Error-Daemon nicht zerstoeren!\n";
- }
- return 0;
-}
-