Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/secure/news.c b/secure/news.c
new file mode 100644
index 0000000..751c887
--- /dev/null
+++ b/secure/news.c
@@ -0,0 +1,566 @@
+// 18.Dez 1996 - Loco@Morgengrauen
+// 8. Feb 1995 - Jof@MorgenGrauen
+// 5. Juli 1992 - Jof@MorgenGrauen
+// 6. Juli 1992 - Jof@MorgenGrauen
+// Clear-Groups-Mechanismus eingebaut. Die 2 Konstanten TIME_TO_CLEAR und
+// MIN_TOUCHED muessen def. sein. Alle TIME_TO_CLEAR Sekunden werden die
+// Newsgroups, die seit dem letzten Clear seltener als MIN_TOUCHED Sekunden
+// beruehrt wurden, aus dem Cache genommen
+
+// 1. Februar 1995 - Jof@MorgenGrauen
+// Rewrite (Mappings benutzen, Accessinfos im Speicher halten)
+
+
+// Datenstrukturen:
+
+// Newsgroups: grouplist ist ein Mapping mit einem Eintrag pro Newsgroup.
+// Die Keys sind die Gruppennamen, Daten:
+// 0 Zeit des letzen Artikels
+// 1 Besitzer der Gruppe
+// 2 Savefille-Name
+// 3 Expire-Zeit
+// 4 Array mit Loesch-Berechtigten
+// 5 Array mit Scheib-Berechtigten
+// 6 Array mit Leseberechtigten
+// 7 Mindest-Level, um Artikel zu loeschen
+// 8 Mindest-Level, um Artikel zu posten
+// 9 Mindest-Level, um Artikel zu lesen
+// 10 Max. Anzahl Nachrichten in der Gruppe
+
+// Die Nachrichten selber stehen in einem Array.
+
+// Eine nachricht ist ein Array mit den folgenden Elementen:
+// 0 (*) string writer;
+// 1 (*) string id; Mudname+":"+time()+":"+group zur Zeit
+// 2 (*) string time;
+// 3 string title;
+// 4 string message;
+
+// Die mit (*) gekennzeichneten Eintraege setzt der Daemon selber
+
+// Funktionen:
+// Returnvalues: 0 = Parameter error
+// 1 = Ok.
+// -1 = no permission
+// -2 = no such group/group already existing
+//
+// Diese Returnvalues stehen fuer alle Funktionen
+
+// AddGroup(groupname, owner, savefile);
+// Funktion klar, kann nur von Erzmagiern aufgerufen werden
+// -3 = no owner, -4 = savefile already in use
+//
+// RemoveGroup(groupname);
+// Ebenfalls nur fuer Erzmagier
+//
+// SetGroup(groupname, dlevel, wlevel, rlevel, maxmessages, expire);
+// Erzmagier und der Groupowner koennen die nutzen. Legt Level, ab dem je-
+// mand aus der Gruppe loeschen kann (dlevel), in die Gruppe schreiben
+// kann (wlevel), die Gruppe lesen kann (rlevel) und die max. Anzahl Nach-
+// richten in der Gruppe fest.
+//
+// AddAllowed(groupname, deleters, writers, readers);
+// Erzmagier/Owner koennen Arrays mit Namen von fuer die Gruppe loesch/
+// schreib/lese-Berechtigten fuer die Gruppe angeben.
+//
+// RemoveAllowed(groupname, deleters, writers, readers); analog
+//
+// WriteNote(message); klar
+// -3 = Max number of msgs exceeded
+//
+// RemoveNote(boardname, notenummer); notenummer>=0;
+// -3 = No such note
+//
+// GetNotes(boardname); gibt einen Array mit den Notes zurueck.
+//
+// AskAllowedWrite(); return wie bei WriteNote, stellt fest, ob ein Player
+// eine Note aufhaengen darf oder nicht
+//
+// GetNewsTime([boardname]); gibt zurueck, wann am entsprechenden Brett zum
+// letzten Mal eine Note befestigt wurde. Falls kein boardname angegeben
+// wird, liefert GetNewsTime() den Zeitpunkt, zu dem ueberhaupt eine neue
+// Note aufgehaengt wurde.
+//
+#pragma strict_types
+#pragma no_clone
+#pragma no_shadow
+#pragma no_inherit
+#pragma verbose_errors
+#pragma combine_strings
+//#pragma pedantic
+//#pragma range_check
+#pragma warn_deprecated
+
+#include "/secure/wizlevels.h"
+#include <defines.h>
+#include <config.h>
+#include <news.h>
+
+#define WTIME 0
+
+private int security( string name );
+
+mixed saveload; // Diese Variable ist als einzige nicht nosave ist und dient
+ // Uebertragen von Daten in/aus savefiles
+
+nosave mapping grouplist; // Groups und ihre save-Files, zudem LastTime
+nosave int lasttime; // Um zu vermeiden, dass 2 Notes identische Uhrzeit==id
+ // haben, wird die jeweils letzte Zeit gespeichert.
+
+nosave mapping cache = ([]); // cache fuer die Gruppeninhalte
+
+void create() {
+ seteuid(getuid(this_object()));
+ if (!restore_object(NEWSPATH+"GroupList"))
+ grouplist=m_allocate(0,G_MESSAGES);
+ else
+ grouplist=saveload;
+ // ersten reset sobald wie moeglich. ;-)
+ set_next_reset(1);
+}
+
+int AddGroup(string name, string owner)
+{
+ mixed *group;
+ string savefile, *savefilea;
+ int i;
+
+ if (!name || !owner) return 0;
+
+ if (!ARCH_SECURITY || process_call()) return -1; // Darf nicht
+
+ if (member(grouplist, name)) return -2; // Gibt es schon
+
+ if (file_size("/"+SAVEPATH+owner[0..0]+"/"+owner+".o")<0) return -3;
+
+ savefilea = old_explode(name,".");
+ savefile = implode(savefilea,"/");
+ if (file_size(NEWSPATH+savefile+".o")>=0) return -4;
+
+ // Notwendige Directories anlegen
+ for (i = 0; i < sizeof(savefilea)-1; i++) {
+ mkdir(NEWSPATH+implode(savefilea[0..i],"/"));
+ }
+
+ group=({});
+ grouplist+=([name:0;owner;savefile;-1;({});({});({});20;0;0;80]);
+ save_group_list();
+ save_group(name,group);
+ return 1;
+}
+
+int RemoveGroup(string name)
+{
+ int num;
+
+ if (!name) return 0;
+
+ if (!security(name) || process_call()) return -1; // Darf nicht
+
+ if (!mappingp(grouplist) || !member(grouplist,name))
+ return -2; // -2 no such group
+
+ catch(rm(NEWSPATH+grouplist[name,G_SAVEFILE]+".o");publish);
+ m_delete(grouplist,name);
+
+ save_group_list();
+
+ return 1;
+}
+
+int SetGroup(string name,int dlevel,int wlevel,int rlevel,int maxmessages,int expire)
+{
+ mixed *group;
+
+ if (!member(grouplist,name)) return -2;
+ if (grouplist[name,G_OWNER]!=user_euid() &&
+ (!security(name) || process_call())) return -1;
+
+ grouplist[name,G_DLEVEL]=dlevel;
+ grouplist[name,G_WLEVEL]=wlevel;
+ grouplist[name,G_RLEVEL]=rlevel;
+ grouplist[name,G_MAX_MSG]=maxmessages;
+ grouplist[name,G_EXPIRE]=expire;
+
+ save_group_list();
+ return 1;
+}
+
+int AddAllowed(string name,mixed deleters,mixed writers,mixed readers)
+{
+ mixed *group;
+
+ if (!member(grouplist,name)) return -2;
+
+ if ( grouplist[name,G_OWNER]!=user_euid() &&
+ (!security(name) || process_call()) && user_euid() != ROOTID )
+ return -1;
+
+ if (stringp(deleters)) deleters=({deleters});
+ if (stringp(writers)) writers=({writers});
+ if (stringp(readers)) readers=({readers});
+
+ if (!deleters) deleters=({});
+ if (!writers) writers=({});
+ if (!readers) readers=({});
+
+ grouplist[name,G_DELETERS]+=deleters;
+ grouplist[name,G_WRITERS]+=writers;
+ grouplist[name,G_READERS]+=readers;
+
+ save_group_list();
+ return 1;
+}
+
+int RemoveAllowed(string name,mixed deleters,mixed writers,mixed readers)
+{
+ mixed *group;
+
+ if (!member(grouplist,name)) return -2;
+
+ if (grouplist[name,G_OWNER]!=user_euid() &&
+ (!security(name) || process_call()) && user_euid() != ROOTID )
+ return -1;
+
+ if (stringp(deleters)) deleters=({deleters});
+ if (stringp(writers)) writers=({writers});
+ if (stringp(readers)) readers=({readers});
+
+ if (!deleters) deleters=({});
+ if (!writers) writers=({});
+ if (!readers) readers=({});
+
+ grouplist[name,G_DELETERS]-=deleters;
+ grouplist[name,G_WRITERS]-=writers;
+ grouplist[name,G_READERS]-=readers;
+
+ save_group_list();
+ return 1;
+}
+
+static string user_euid()
+{
+ if (previous_object()) {
+ if (geteuid(previous_object())==ROOTID) return ROOTID;
+ if (geteuid(previous_object())=="p.daemon") return "p.daemon";
+ if (load_name(previous_object())=="/obj/mpa") return geteuid(RPL);
+ }
+ return secure_euid();
+}
+
+#define F_DELETE 0
+#define F_READ 1
+#define F_WRITE 2
+#define F_ADMIN 3
+#define F_KEEPNAME 4
+
+private int security( string name )
+{
+ if ( grouplist[name,G_DLEVEL] >= ARCH_LVL
+ || grouplist[name,G_WLEVEL] >= ARCH_LVL
+ || grouplist[name,G_RLEVEL] >= ARCH_LVL )
+ return ARCH_SECURITY;
+ else
+ return ELDER_SECURITY;
+}
+
+static int allowed(string name, int mode)
+{
+ string euid;
+ mixed g_level, g_mode;
+
+ if (process_call()) return 0;
+
+ euid=user_euid();
+
+ if (euid==ROOTID) return 1;
+
+ switch(mode) {
+ case F_KEEPNAME: return (euid=="p.daemon");
+ case F_WRITE: if (euid=="p.daemon") return 1;
+ g_level=G_WLEVEL; g_mode=G_WRITERS; break;
+ case F_ADMIN: if (!(security(name)||grouplist[name,G_OWNER]==euid))
+ return 0;
+ g_level=G_DLEVEL; g_mode=G_DELETERS; break;
+ case F_DELETE: if (euid=="p.daemon") return 1;
+ g_level=G_DLEVEL; g_mode=G_DELETERS; break;
+ case F_READ: g_level=G_RLEVEL; g_mode=G_READERS; break;
+ default: return 0;
+ }
+
+ if (grouplist[name,G_OWNER] != euid && !ARCH_SECURITY &&
+ grouplist[name,g_level] > query_wiz_level(euid) &&
+ member(grouplist[name, g_mode], euid)==-1)
+ return 0; // No such group for the requestor :)
+ return 1;
+}
+
+int WriteNote(mixed message,mixed keepname)
+{
+ mixed *group;
+ int uidok,tmp;
+ string name;
+
+ if (!pointerp(message) || sizeof(message)!=6) return 0;
+
+ if (!pointerp(group=load_group(name=message[M_BOARD]))) return -2;
+
+ if (!allowed(name, F_WRITE)) return -1;
+
+ if (sizeof(group)>=grouplist[name,G_MAX_MSG]) return -3;
+
+ if (!keepname || !allowed(name, F_KEEPNAME))
+ message[M_WRITER]=capitalize(geteuid(this_interactive()||previous_object()));
+
+ if (lasttime>=time()) lasttime++;
+ else lasttime=time();
+ message[M_TIME]=lasttime;
+ message[M_ID]=MUDNAME+":"+lasttime;
+ group+=({message});
+ grouplist[name,WTIME]=lasttime;
+ save_group(name,group);
+ save_group_list();
+ return 1;
+}
+
+int RemoveNote(string name, int note)
+{
+ int num;
+ mixed *group;
+
+ if ((note<0) && (name=="dwnews"))
+ {
+ group=({});
+ grouplist[name,WTIME]=0;
+ save_group(name,group);
+ save_group_list();
+ return 1;
+ }
+
+ if (note<0) return 0;
+
+ if (!pointerp(group=load_group(name))) return -2;
+
+ int count=sizeof(group);
+ if (count<=note)
+ return -3;
+
+ if (!allowed(name, F_DELETE) &&
+ lower_case(group[note][M_WRITER])!=user_euid()) return -1;
+
+ if (count==1)
+ group=({});
+ else if (!note)
+ group = group[1..];
+ else if (note == count-1)
+ group = group[0..<2];
+ else
+ group=group[0..note-1]+group[note+1..];
+
+ if (sizeof(group))
+ grouplist[name,WTIME]=group[<1][M_TIME];
+ else
+ grouplist[name,WTIME]=0;
+ save_group(name,group);
+ save_group_list();
+ return 1;
+}
+
+mixed GetNotes(string name)
+{
+ mixed *group;
+
+ if (!pointerp(group=load_group(name))) return -2;
+ if (!allowed(name, F_READ)) return -2;
+ return(deep_copy(group)); // COPY it
+}
+
+static void dump_file(string filename,mixed news)
+{
+ int i;
+
+ for (i=0;i<sizeof(news);i++)
+ write_file(filename,news[i][M_TITLE]+" ("+news[i][M_WRITER]+", "+
+ dtime(news[i][M_TIME])[5..26]+"):\n"+
+ news[i][M_MESSAGE]+"\n-----------------------------------------------------------------------------\n\n\n\n");
+}
+
+protected varargs void expire(string grp,int etime)
+// etime ist anfangs in Tagen und bezeichnet das max. Alter, was Artikel in
+// der Gruppe haben duerfen.
+{
+ mixed *group;
+
+ if (!pointerp(group=load_group(grp))) return;
+ if (etime)
+ {
+ if (etime>0)
+ etime=etime*60*60*24;
+ }
+ else
+ etime=grouplist[grp,G_EXPIRE];
+ if (etime<=0)
+ return;
+
+ int to_expire=time()-etime;
+ int size=sizeof(group);
+ if (!size) return;
+
+ int first_to_keep = size; // ja, ist noch eins zu hoch
+ // solange runterlaufen bis man ein element findet, welches geloescht werden
+ // soll. first_to_keep bleibt dann eins hoeher als das.
+ while ( first_to_keep && group[first_to_keep-1][M_TIME]>to_expire)
+ --first_to_keep;
+ // first_to_keep kann jetzt auf eins hinter dem letzten Element zeigen (==
+ // size). Das wird unten beruecksichtigt.
+
+ if (!first_to_keep) // alle behalten?
+ return;
+ // Zu loeschende Artikel wegschreiben.
+ dump_file("news/OLD."+grp,group[0..first_to_keep-1]);
+ // dann loeschen
+ if (first_to_keep == size) // alle wegwerfen?
+ group=({});
+ else
+ group=group[first_to_keep..size-1];
+
+ save_group(grp,group);
+}
+
+void dump_group(string grp)
+{
+ int to_expire,size,last;
+ mixed *group;
+
+ if (!ARCH_SECURITY || process_call()) return;
+ if (!pointerp(group=load_group(grp))) return;
+ size=sizeof(group);
+ last=size;
+ if (!last) return;
+ dump_file("news/DUMP."+grp,group[0..last-1]);
+}
+
+protected void expire_all(string *keys) {
+ // neuen call_out fuer den Rest setzen
+ if (sizeof(keys) > 1)
+ call_out(#'expire_all,15,keys[1..]);
+ // und erste Gruppe expiren
+ expire(keys[0]);
+}
+
+void reset() {
+ // naechstes Expire und damit Reset in einem tag
+ set_next_reset(86400);
+ // alte call_outs ggf. entfernen.
+ while(remove_call_out(#'expire_all)>=0);
+ // gruppenliste holen und callout auf expire_all starten
+ if (sizeof(grouplist)) {
+ call_out(#'expire_all,10,m_indices(grouplist));
+ }
+}
+
+static void save_group(string grp,mixed group)
+{
+ saveload=group; // Do NOT save the accessed-Info
+ cache[grp] = group;
+ save_object(NEWSPATH+grouplist[grp,G_SAVEFILE]);
+ saveload=0;
+}
+
+static void save_group_list()
+{
+ saveload=grouplist;
+ save_object(NEWSPATH+"GroupList");
+ saveload=0;
+}
+
+static mixed load_group(string name)
+{
+ int num;
+ mixed *ret;
+
+ if(!member(grouplist,name)) return -1;
+
+ if (member(cache, name)) {
+ ret = cache[name];
+ }
+ else {
+ restore_object(NEWSPATH+grouplist[name,G_SAVEFILE]);
+ if (!pointerp(saveload))
+ saveload=({});
+ ret=saveload;
+ cache[name] = saveload;
+ saveload=0;
+ }
+ return ret;
+}
+
+mixed GetGroups()
+{
+ mixed *returnlist;
+ int i,group,slevel;
+ string seuid;
+
+ returnlist=sort_array(m_indices(grouplist),#'>); //');
+ if (ARCH_SECURITY && !process_call())
+ return returnlist;
+
+ seuid = user_euid();
+ slevel = secure_level();
+
+ for (i=sizeof(returnlist)-1;i>=0;i--)
+ if (!(grouplist[returnlist[i],G_RLEVEL]<=slevel ||
+ grouplist[returnlist[i],G_OWNER]==seuid ||
+ member(grouplist[returnlist[i],G_READERS], seuid)!=-1))
+ returnlist=returnlist[0..i-1]+returnlist[i+1..];
+ return returnlist;
+}
+
+int AskAllowedWrite(string n)
+{
+ mixed *group;
+
+ if (!member(grouplist,n)) return -2;
+ if (!pointerp(group=load_group(n))) return -2;
+
+ if (grouplist[n,G_OWNER] != user_euid() &&
+ !ARCH_SECURITY &&
+ grouplist[n,G_WLEVEL]>secure_level() &&
+ member(grouplist[n,G_WRITERS],user_euid())==-1)
+ return -1;
+
+ if (sizeof(group)>=grouplist[n,G_MAX_MSG]) return -3;
+ return 1;
+}
+
+// Wichtig ...
+
+int query_prevent_shadow()
+{
+ return 1;
+}
+
+mixed GetNewsTime(string boardname)
+
+{
+ int i, ltime, j;
+ mixed *keys;
+
+ if (!boardname)
+ {
+ ltime=-1;
+ for (i=sizeof(keys=m_indices(grouplist))-1;i>=0;i--)
+ if (ltime<(j=grouplist[keys[i],WTIME])) ltime=j;
+ return ltime;
+ }
+ if (!member(grouplist,boardname)) return -1;
+ return grouplist[boardname,WTIME];
+}
+
+mixed* GetGroup(string name)
+{
+ if (process_call()) return 0;
+ if (extern_call() && !allowed(name, F_ADMIN)) return 0;
+#define gl(x) grouplist[name,x]
+ return ({name,gl(1),gl(2),gl(3),gl(4),gl(5),gl(6),gl(7),gl(8),gl(9),gl(10),load_group(name)});
+}