| // 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 (!({int})master()->find_userinfo(owner)) 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(NEWSPATH"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(NEWSPATH"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)}); |
| } |