// // Enkel databas i en l}ng fil. // // Formatet f|r filen {r: // post \n\n post // Formatet f|r varje post {r: // f{lt \n f{lt \n f{lt ... s} m}nga som det nu {r... // inga f{lt f}r vara tomma. // // #define DEBUG #define DATABASEFILE "/usr/www/html/svmud/spelare/linus/data/DB" #define PASSWDFILE "/usr/www/html/svmud/spelare/linus/data/passwd" #define SVMUDPLAYERS "/usr/svmud/lib/spelare/" #define ADMIN "linus" inherit "http"; array (array(string)) data = ({ }); void load_data() { data = map_array(explode(read_bytes(DATABASEFILE), "\n\n"), lambda(string record) { return explode(record, "\n") - ({ "", }); }) - ({ ({ }) }); } void save_data() { rm(DATABASEFILE + ".old"); mv(DATABASEFILE, DATABASEFILE + ".old"); write_file(DATABASEFILE, implode(map_array(data, lambda(array(string) record) { return implode(record,"\n"); }), "\n\n")); } void prepare_to_save() { remove_call_out(save_data); call_out(save_data, 1); } // These macros are used to find the correct record. #define RECORD_NAME(rec) (rec)[0] #define RECORD_PASSWORD(rec) (rec)[1] #define RECORD_REALNAME(rec) (rec)[2] #define RECORD_REALADDRESS(rec) (rec)[3] #define RECORD_PHONE(rec) (rec)[4] #define RECORD_EMAIL(rec) (rec)[5] #define RECORD_HOMEPAGE(rec) (rec)[6] #define RECORD_PICTURE(rec) (rec)[7] #define RECORD_ORIGINALLYFROM(rec) (rec)[8] #define RECORD_BECAMEWIZARD(rec) (rec)[9] #define RECORD_OTHER_INFO(rec) (rec)[10] #define RECORD_LAST_MODIFIED(rec) (rec)[11] #define VERIFY_ARRAY_SIZE(rec) while (sizeof(rec) < 12) { rec += ({ "" }); } // Removes all items with the name name from data. void remove_from_array(string name) { int i; for (i = 0; i < sizeof(data); i++) { if (RECORD_NAME(data[i]) == name) { data -= ({ data[i], }); i--; } } } void add_to_array(array(string) record) { int i; for(i = 0; i < sizeof(record); i++) { record[i] = replace(record[i], ({ "\n", "\r", }), ({ " ", " ", })); if (record[i] == "") record[i] = "0"; } data += ({ record }); } mapping data_index; // Resets the index void reset_index() { data_index = 0; } // Builds or rebuilds the index. void rebuild_index() { data_index = mkmapping(map_array(data, lambda(array(string) record) { return RECORD_NAME(record); }), data); } // Builds the index if not already built. void build_index() { if (mappingp(data_index)) return; rebuild_index(); } void create() { load_data(); reset_index(); } // This returns 0 if not found. array(string) get(string name) { build_index(); if (arrayp(data_index[name])) return map_array(data_index[name], lambda(string info) { if (info == "0") return ""; else return info; }); else return 0; } // Adds or modifies an entry. void put(array(string) record) { reset_index(); remove_from_array(RECORD_NAME(record)); add_to_array(record); prepare_to_save(); } void delete(string name) { reset_index(); remove_from_array(name); prepare_to_save(); } array(string) all_entries() { build_index(); return indices(data_index); } // End of database things string filename; string basename(string name) { array(string) a = explode(name,"/"); return filename = a[sizeof(a) - 1]; } // Things that help in the authentication // Generate a new record containing name and password for a user not in // the database. // First search in the passwd-format-like file. Then in the svmud data files. mapping passwd = 0; array(string) generate_new_passwd(string name) { name = lower_case(name); if (passwd == 0) { // Read the passwd-format file. passwd = sum(@map_array((explode(read_bytes(PASSWDFILE) || "", "\n")), lambda(string entry) { array(string) arr = explode(entry, ":"); if (sizeof(arr) < 2) return ([ ]); return ([arr[0]:arr[1]]); })); } if (passwd[name]) { return ({ name, passwd[name], }); } return 0; } array(string) generate_new_datafile(string name) { string pass; string filecont; name = lower_case(name); if ((filecont = read_bytes(SVMUDPLAYERS + name + ".o")) && sscanf(filecont, "%*s\npassword \"%s\"", pass)) { return ({ name, pass, }); } return 0; } // Convert an auth record to a name. string auth_to_name(array(string) arr) { return lower_case(arr[1]); } string auth_to_password(array(string) arr) { return arr[2]; } // Return true if the auth record identifies a user correctly // Actually it returns 1 if in the database, 2 if in the passwd-style file // and 3 if in the datafile (4 if the password is allready identified by // the user db of roxen. int auth_is_correct(array(string) arr) { array(string) record; if (arr && sizeof(arr) >= 3 && arr[0] && stringp(auth_to_name(arr)) && generate_new_datafile(auth_to_name(arr))) return 4; if (!(arr && sizeof(arr) >= 3 && stringp(auth_to_name(arr)) && stringp(auth_to_password(arr)))) return 0; record = get(auth_to_name(arr)); if (record && sizeof(record) >= 2 && stringp(RECORD_PASSWORD(record)) && RECORD_PASSWORD(record) != "" && crypt(auth_to_password(arr), RECORD_PASSWORD(record))) return 1; record = generate_new_passwd(auth_to_name(arr)); if (record && sizeof(record) >= 2 && crypt(auth_to_password(arr), RECORD_PASSWORD(record))) return 2; record = generate_new_datafile(auth_to_name(arr)); if (record && sizeof(record) >= 2 && crypt(auth_to_password(arr), RECORD_PASSWORD(record))) return 3; return 0; } // Quote "dangerous" characters. string quote(string in) { return replace(in, ({ "\"", "<", ">", }), ({ """, "<", ">", })); } // Returns the info about one person. string info_about(string name, int with_pictures) { array(string) record = get(lower_case(name)); if (record) { VERIFY_ARRAY_SIZE(record); return (with_pictures && RECORD_PICTURE(record) != "" ? "" : "") + "

" + capitalize(name) + "

\n" + "
"
	    + quote(RECORD_REALNAME(record))
	    + "\n"
	    + implode(explode(quote(RECORD_REALADDRESS(record)),", "), "\n")
	    + "
" + "\n" + (RECORD_PHONE(record) != "" ? "Telefon: " + quote(RECORD_PHONE(record)) : "") + (RECORD_PHONE(record) != "" && RECORD_EMAIL(record) != "" ? ", " : "") + (RECORD_EMAIL(record) != "" ? "email: " + quote(RECORD_EMAIL(record)) + "" : "") + "

\n" + (RECORD_ORIGINALLYFROM(record) != "" ? capitalize(name) + " kommer ursprungligen från " + quote(RECORD_ORIGINALLYFROM(record)) + ".\n" : "") + "\n" + (RECORD_BECAMEWIZARD(record) != "" ? capitalize(name) + " blev magiker den " + quote(RECORD_BECAMEWIZARD(record)) + ".\n" : "") + "\n" + (RECORD_OTHER_INFO(record) != "" ? quote(RECORD_OTHER_INFO(record)) + "\n" : "") + "\n" + (RECORD_HOMEPAGE(record) != "" ? capitalize(name) + " har en egen hemsida." : "") + (RECORD_LAST_MODIFIED(record) != "" ? "

\nInformationen om " + capitalize(name) + " ändrades senast " + RECORD_LAST_MODIFIED(record) : "") + "
\n"; } else { return "Ingen information finns i databasen om " + name + "\n"; } } #define LENKARNA "[Ändra/lägg till din information] "\ + "[All info utan bilder] " \ + "[All info med bilder] " \ + "[Bara de som har hemsidor] " // Returnerar ett snabbindex där alla spelarna finns med indexerat på bokstav string snabbindex() { string current_letter = "0"; array (string) arr = sort_array((array*)all_entries(), 0, 0); string output = "

\n"; while (sizeof(arr)) { if (current_letter != arr[0][0..0]) { current_letter = arr[0][0..0]; output += "
" + capitalize(current_letter) + "
"; } output += "" + capitalize(arr[0]) + "\n"; arr = arr[1.. sizeof(arr)]; } output += "
\n"; return output; } string the_entire_contents(int with_pictures) { return LENKARNA + "
\n" + "

Följande spelare finns med (" + sizeof(all_entries()) + " st)

\n" + snabbindex() + "
\n" + "

Information om spelarna

\n" + implode(map_array(sort_array((array*)all_entries(), 0, 0), info_about, with_pictures), "\n\n") + "
\n" + LENKARNA; } // Funktoinen returnerar en lista med bara namn och länkar till deras hemsidor // De som inte har hemsidor blir bortsorterade. string the_list_of_links() { #define with_pictures (1) return LENKARNA + "
\n\n" + "
\n" + LENKARNA; #undef with_pictures } // Funktionen returnerar det som administrat|ren har f|r att f} fram formul{r // f|r att editera andras information. string admin_knapp(string who) { return "

Administratörskommandon:

\n" + "
\n" + "\n" + "\n" + "\n" + "
\n" + "Annan:
\n" + "\n" + "\n" + "\n" + "
\n" + "
\n"; } // string form_for(string who, int is_admin, array(string) record, int first_time_around) { VERIFY_ARRAY_SIZE(record); return (is_admin ? admin_knapp(who) : "") + "

Informationen om " + capitalize(who) + " till SvenskMUDs vem är vem ser ut så här:

\n" + info_about(who, 1) + "
\n" + "
\n" + "

Här kan du ändra informationen

\n" + "Tänk på att inte stressa när du fyller i här. Kontrollera att " + "du stavat rätt efter att du skickat in det och om något är fel " + "så ändra igen så att det blir rätt. Använd inte hemmagjorda " + "förkortningar, gladmän eller ellips." + "

Jag (Linus) kommer, när jag hinner, gå omkring och rätta till " + "det värsta slarvet så att denna lista blir vacker och användbar." + "

\n" + "\n" + "\n" + "
\n" + "
Riktigt namn:
\n" + "
Riktig adress (om du inte vill uppge din riktiga adress så lämna tomt.) (För att få nyrad i din adress använder du komma mellanslag. Du skriver alltså Byvägen 3, S-123 45 MUDDEVALLA):\n" + "
\n" + "
Telefonnummer (om du inte vill uppge ditt telefonnummer så lämna tomt):\n" + "
\n" + "
Email (om du inte har någon email-adress så lämna tomt):\n" + "
\n" + "
Hemsida (En url. En url börjar med http:, gopher: eller liknande) (Om du inte har en hemsida så lämna tomt):\n" + "
\n" + "
En bild på dig (en url) (Om du inte har en bild liggande tillgänglig via internet så lämna tomt):
\n" + "
Ursprungligen från (om du inte känner att du kommer någonstans ifrån, dvs att du fortfarande bor kvar, så lämna tomt):
\n" + "
Blev magiker ett datum (om du inte blivit magiker än eller inte vet så lämna tomt.) (använd formatet dag månadmedbokstäver år, Ex 1 januari 1901):\n" + "
\n" + "
Annat (Här kan du skriva vad som helst egentligen. Skriv korrekta meningar dvs börja med stor bokstav och sluta med punkt. Om du inte har något att skriva så lämna tomt. Du behöver inte skriva något. Om du skriver kan du tänka på att det kan vara trevligt om du skriver allting i tredje person singularis.):
\n" + "
\n" + "Jag godkänner att informationen som jag nu skickar in blir " + "tillgänglig för alla på internet genom att trycka på" + "\n" + "
\n" + "
\n" + "\n" + "\n" + "Jag vill inte längre finnas med i registret och därför " + "vill jag" + "\n" + "
\n" + "
Du kan också gå tillbaka till hela lista" + (first_time_around ? " utan att spara informationen" : "") + ""; } // Funktioner som anropas n{r saker skall modifieras. string do_submit(string who, mapping vars, string new_password, int admin) { array(string) arr = get(who) || ({ who, }); VERIFY_ARRAY_SIZE(arr); if (new_password) RECORD_PASSWORD(arr) = new_password; RECORD_REALNAME(arr) = vars["realname"] || ""; RECORD_REALADDRESS(arr) = vars["realaddress"] || ""; RECORD_PHONE(arr) = vars["phone"] || ""; RECORD_EMAIL(arr) = vars["email"] || ""; RECORD_HOMEPAGE(arr) = vars["homepage"] || ""; RECORD_PICTURE(arr) = vars["picture"] || ""; RECORD_ORIGINALLYFROM(arr) = vars["originallyfrom"] || ""; RECORD_BECAMEWIZARD(arr) = vars["becamewizard"] || ""; RECORD_OTHER_INFO(arr) = vars["otherinfo"] || ""; RECORD_LAST_MODIFIED(arr) = ctime(time())[0..23] + (admin ? " av " + capitalize(ADMIN) : ""); put(copy_value(arr)); return "Informationen mottagen." + "
\n" + form_for(who, 0, arr, 0); } string do_remove(string who, mapping vars, string new_password) { array(string) arr = get(who); if (arr) { delete(who); } return "Informationen mottagen." + "
\n" + form_for(who, 0, ({ who, }), 0); } // This function simply adds the header and footer of all the requests. #define SURROUND(str, tag) "<" + tag + ">\n" + str + "\n\n" #define HEAD(str) SURROUND(str, "head") #define TITLE(str) SURROUND(str, "title") #define BODY(str) SURROUND(str, "body") #define H1(str) SURROUND(str, "h1") string add_decorations(string title, string data) { return HEAD(TITLE(title)) + BODY(H1(title) + "
\n" + data + "
\n" + "Det är Linus som sköter det här registret så hör av dig till honom om det är skumheter med det."); } // Alternatives for parse // - No special requests: // generate a list of the entire database // - op=update - no credentials // somebody pressed his update button, demand the credentials // - op=update - credentials // check the credentials if ok - show the form with contents. // if not ok - ask again. // - op=update - credentials - fields // update the fields. // - op=submit - enter the information // - op=remove - remove the information string|mapping parse(object request) { basename(request->realfile); if (request->variables["op"] != "update" && request->variables["op"] != "submit" && request->variables["op"] != "remove") { // We want the list if (request->variables["op"] == "links") // We want the shorted list. return add_decorations("Vem är vem i SvenksMUD - de med hemsidor", the_list_of_links()); return add_decorations("Vem är vem i SvenskMUD - hela listan", the_entire_contents(request->variables["pictures"] == "yes")); } else { int auth_type; #ifdef DEBUG mixed requestcopy = copy_value(request); #endif if ((auth_type = auth_is_correct(request->auth))) { // We have credentials and they are correct. // Generate a form or handle the contents of a form. array(string) record = get(auth_to_name(request->auth)) || ({ auth_to_name(request->auth), }); array(string) new; if (auth_type == 2) new = generate_new_passwd(auth_to_name(request->auth)); if (auth_type == 3) new = generate_new_datafile(auth_to_name(request->auth)); if (request->variables["op"] == "submit") { if (RECORD_NAME(record) == ADMIN) { // The admin can update anything. return add_decorations("Vem är vem - Administratörsuppdateringens resultat.", do_submit(lower_case(request->variables["name"]), request->variables, new ? RECORD_PASSWORD(new) : 0, 1)); } else { return add_decorations("Vem är vem - Resultatet av uppdateringen.", do_submit(RECORD_NAME(record), request->variables, new ? RECORD_PASSWORD(new) : 0, 0)); } } else if (request->variables["op"] == "remove") { if (RECORD_NAME(record) == ADMIN) { // The admin can update anything. return add_decorations("Vem är vem - Administratörsuppdateringens resultat.", do_remove(lower_case(request->variables["name"]), request->variables, 0)); } else { return add_decorations("Vem är vem - Resultatet av uppdateringen.", do_remove(RECORD_NAME(record), request->variables, 0)); } } else { if (RECORD_NAME(record) == ADMIN && stringp(request->variables["name"])) { record = (get(lower_case(request->variables["name"])) || ({ lower_case(request->variables["name"]), })); return add_decorations("Vem är vem - Administratör fyll i information för " + RECORD_NAME(record), form_for(RECORD_NAME(record), 1, record, 1)); } else { return add_decorations("Vem är vem - Fyll i information för din karaktär: " + capitalize(RECORD_NAME(record)), form_for(RECORD_NAME(record), RECORD_NAME(record) == ADMIN, record, 1)); } } } else { // We don't have the credentials or they are incorrect. return http_auth_required("svenskmudplayer", add_decorations("Otillräcklig identifiering", "Du måste ge korrekt namn och lösenord för en existrerande svenskmuddare.

Ibland kanske inte ens det hjälper. Prova då att ange det lösenord du hade tidigare i Svenskmud eller om du är en ny spelare så finns du nog inte med. Tala då om problemet för Linus så kan han uppdatera lösenordsdatabasen." #ifdef DEBUG + sprintf("

\n%O\n
", request->auth) + sprintf("
\n%O\n
", request->auth && sizeof(request->auth) >= 3 && stringp(auth_to_name(request->auth)) && stringp(auth_to_password(request->auth)) ? generate_new_datafile(auth_to_name(request->auth)) : "arrayen inkorrekt") + sprintf("
\n%O\n
", passwd) + sprintf("

Request:

    \n%s
", implode(map_array(sort(indices(requestcopy)), lambda(string id, object ob) { return sprintf("
  • %s %O\n", id, ob[id]); }, requestcopy), "\n" )) #endif )); } } }