mirror of
git://git.psyced.org/git/psyced
synced 2024-08-15 03:25:10 +00:00
let the past begone in cvs land. welcome to igit igit!
This commit is contained in:
commit
4e601cf1c7
509 changed files with 77963 additions and 0 deletions
72
world/net/http/call.c
Normal file
72
world/net/http/call.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
#include <net.h>
|
||||
#include <text.h>
|
||||
#include <ht/http.h>
|
||||
|
||||
protected mapping sessions = ([ ]);
|
||||
|
||||
string make_session(string nick, int expiry, string jack) {
|
||||
string sid;
|
||||
#ifndef TELEPHONY_EXPIRY
|
||||
# define TELEPHONY_EXPIRY expiry - time()
|
||||
#endif
|
||||
while (sessions[sid = RANDHEXSTRING]);
|
||||
sessions[sid] = ({ nick, expiry, jack });
|
||||
call_out( (: return m_delete(sessions, sid); :), TELEPHONY_EXPIRY);
|
||||
return sid;
|
||||
}
|
||||
|
||||
htget(prot, query, headers, qs) {
|
||||
#ifdef TELEPHONY_SERVER
|
||||
string sid = query["sid"];
|
||||
if (!(sid && sessions[sid])) {
|
||||
// no session found
|
||||
return;
|
||||
}
|
||||
if (sessions[sid][1] < time()) {
|
||||
// session expired
|
||||
return;
|
||||
}
|
||||
|
||||
string ni = sessions[sid][0];
|
||||
string t = query["thats"];
|
||||
|
||||
unless (t) {
|
||||
object uo = find_person(ni);
|
||||
if (!uo || !sendmsg(uo, "_notice_answer_talk_click",
|
||||
"Your phone call request has been clicked upon.", ([
|
||||
"_time_expire" : to_string(sessions[sid][1]),
|
||||
"_check_call" : sessions[sid][2],
|
||||
"_session" : sid,
|
||||
]))) {
|
||||
hterror(prot, R_GATEWTIMEOUT,
|
||||
"User cannot be reached.");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
htok3(prot, 0, "Expires: 0\n");
|
||||
localize(query["lang"], "html");
|
||||
w("_HTML_head");
|
||||
w("_HTML_call", 0, ([
|
||||
// "_path_object": "/static/call.swf",
|
||||
// "_amount_width_object": "330",
|
||||
// "_amount_height_object": "121",
|
||||
"_path_object_local": "/static/local.swf",
|
||||
"_path_object": "/static/remote.swf",
|
||||
"_amount_width_object": "320",
|
||||
"_amount_height_object": "240",
|
||||
// url = rtmp server
|
||||
"_uniform_server_media": TELEPHONY_SERVER,
|
||||
// stream infos (thats, user, expiry, jack)
|
||||
"_QUERY_STRING": qs,
|
||||
"_role": t ? "I": "U",
|
||||
"_nick": ni,
|
||||
"_time_expire": to_string(sessions[sid][1]),
|
||||
"_check_call" : sessions[sid][2],
|
||||
]));
|
||||
w("_HTML_tail");
|
||||
#else
|
||||
hterror(prot, R_NOTIMPLEM, // "_error_unavailable_telephony"
|
||||
"Sorry, no telephony configured on this server.");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
571
world/net/http/configure.c
Normal file
571
world/net/http/configure.c
Normal file
|
@ -0,0 +1,571 @@
|
|||
// $Id: configure.c,v 1.58 2007/06/17 21:07:54 lynx Exp $ // vim:syntax=lpc
|
||||
//
|
||||
// web configurator interface. does a lot of cool things for you,
|
||||
// and it should always learn to do some more. if you don't need or
|
||||
// like it, simply don't load it (from init.ls, or by fetching the url).
|
||||
//
|
||||
#include <net.h>
|
||||
#include <driver.h>
|
||||
|
||||
#if HAS_PORT(HTTP_PORT, HTTP_PATH) || HAS_PORT(HTTPS_PORT, HTTP_PATH)
|
||||
|
||||
#include <text.h>
|
||||
#include <person.h>
|
||||
|
||||
#include <misc.h>
|
||||
inherit NET_PATH "sockets";
|
||||
|
||||
#ifdef WEB_CONFIGURE
|
||||
// should this use something else?
|
||||
# define CONFIGFILE CONFIG_PATH "local.h"
|
||||
|
||||
volatile protected mapping description;
|
||||
|
||||
void create() {
|
||||
sTextPath(0, 0, "html");
|
||||
description = ([
|
||||
// this has all moved into psyced.ini
|
||||
// "CHATNAME" : "Name of this Chat Community",
|
||||
// "DEFPLACE" : "Standard place unregistered users go to",
|
||||
// "ADMINISTRATORS" : "List of administrators <small>(example: "
|
||||
// ""admin1", "admin2", "
|
||||
// ""admin3")</small>",
|
||||
// "__DOMAIN_NAME__" : "Domain name of this server",
|
||||
// "SERVER_HOST" : "Address of this server",
|
||||
// "OSTYPE" : "Your Operating System",
|
||||
// "MACHTYPE" : "The flavour of your processor",
|
||||
// optimise on tunings, like this one?
|
||||
"MAX_VISIBLE_USERS" : "MAX_VISIBLE_USERS",
|
||||
// a bit absurd: specify a file on the fs instead of having a motd textarea
|
||||
"MOTD_FILE" : "The file that contains the IRC-MOTD",
|
||||
]);
|
||||
}
|
||||
|
||||
denyAccess(prot) {
|
||||
hterror(prot, 200, "You are not allowed to use the configure-page. "
|
||||
"You need to be from <i>localhost</i> to do that.");
|
||||
}
|
||||
|
||||
parseConfig(fname) {
|
||||
mapping cv;
|
||||
int size;
|
||||
|
||||
cv = ([ ]);
|
||||
|
||||
if (file_size(fname) <= 0) {
|
||||
return ([ ]);
|
||||
}
|
||||
|
||||
foreach(string line : explode(read_file(fname), "\n")) {
|
||||
mixed key, value;
|
||||
|
||||
if (sscanf(line, "#define%t%s%t%s", key, value)
|
||||
|| sscanf(line, "#define%t%s", key)
|
||||
|| sscanf(line, "#%tdefine%t%s%t%s", key, value)
|
||||
|| sscanf(line, "#%tdefine%t%s", key)
|
||||
) {
|
||||
//if (dummy=="" && index(key, ' ')==-1 && index(key, '\t')==-1)
|
||||
// && (member(description, key) != -1))
|
||||
cv[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return cv;
|
||||
}
|
||||
|
||||
saveConfig(string fname, mapping config, mapping del) {
|
||||
string file, key, value, tail;
|
||||
int added;
|
||||
|
||||
unless (mappingp(del)) {
|
||||
del = ([ ]);
|
||||
}
|
||||
|
||||
if (file_size(fname) <= 0) {
|
||||
if (abbrev("place/", fname)) {
|
||||
file = w("_PAGES_configure_room_new");
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
file = read_file(fname);
|
||||
}
|
||||
added = 0;
|
||||
foreach (key, value : config) {
|
||||
// re scheint keine + syntax zu beherrschen
|
||||
P2(("===> %O\n", value))
|
||||
if (to_string(to_int(value)) != value && value != "") {
|
||||
unless (value[0] == '"')
|
||||
value = "\"" + value;
|
||||
|
||||
unless (value[<1] == '"')
|
||||
value += "\"";
|
||||
}
|
||||
|
||||
if (sizeof(regexp(({ file }),
|
||||
"#([ \t]*)define([ \t][ \t]*)"+key+
|
||||
"([ \t][ \t]*)[^\n]*"))) {
|
||||
tail = "([ \t][ \t]*)[^\n]*";
|
||||
} else if (sizeof(regexp(({ file }),
|
||||
"#([ \t]*)define([ \t][ \t]*)"+key))) {
|
||||
tail = "";
|
||||
} else {
|
||||
// adden
|
||||
file = regreplace(file,
|
||||
"#include <place.gen>",
|
||||
"#define "+key+" "+
|
||||
(value != "" ? " "+value : "")+
|
||||
"\n#include <place.gen>", 0);
|
||||
added = 1;
|
||||
|
||||
}
|
||||
|
||||
unless (value == "" && added == 0) {
|
||||
file = regreplace(file,
|
||||
"#([ \t]*)define([ \t][ \t]*)"+key+tail,
|
||||
"#\\1define "+key+"\t"+value, 0);
|
||||
} else if (added == 0){
|
||||
file = regreplace(file,
|
||||
"#([ \t]*)define([ \t][ \t]*)"+key+tail,
|
||||
"#\\1define "+key, 0);
|
||||
}
|
||||
// old ldmud requires 4th argument
|
||||
// if (t == file) printf("Could not change %s into %O\n", key, value);
|
||||
}
|
||||
|
||||
foreach (key, value : del) {
|
||||
file = regreplace(file,
|
||||
"#([ \t]*)define([ \t][ \t]*)"+key+"[^\n]*\n",
|
||||
"", 0);
|
||||
}
|
||||
rm(fname);
|
||||
write_file(fname, file);
|
||||
return w("_PAGES_configure_advice_restart") + "<font size=6><pre>\n" +
|
||||
"Congratulations, this is your new configuration file:\n" +
|
||||
"</pre><font color=green><plaintext>\n" + file;
|
||||
}
|
||||
|
||||
htget(prot, query, headers, qs) {
|
||||
string s; // output buffer
|
||||
int trustworthy = legal_host(query_ip_number(), HTTP_PORT, "http", 0);
|
||||
|
||||
if (trustworthy < 7) {
|
||||
denyAccess(prot);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (file_size(CONFIGFILE) <= 0) {
|
||||
hterror(prot, 404, "You don't have any configfile, do you?");
|
||||
return 1;
|
||||
}
|
||||
|
||||
htok3(prot, "text/html", "Cache-Control: no-cache\n");
|
||||
|
||||
switch (query["option"]) {
|
||||
case "user_mgm":
|
||||
s = w("_PAGES_configure_user",
|
||||
([ "_title" : "User Management" ]));
|
||||
break;
|
||||
case "list_users":
|
||||
write(w("_PAGES_configure_user_list",
|
||||
([ "_title" : "User List" ])));
|
||||
list_sockets();
|
||||
return 1;
|
||||
case "block_modify":
|
||||
if (query["ip"] && query["ip"] != 0) {
|
||||
object ob;
|
||||
|
||||
DAEMON_PATH "hosts"->modify(query["ip"]);
|
||||
foreach (ob : users()) {
|
||||
if (abbrev(query["ip"], query_ip_number(ob))) {
|
||||
log_file("BEHAVIOUR",
|
||||
"[%s] %O blocks %O (%s)\n",
|
||||
ctime(), ME, ob, query["ip"]);
|
||||
ob -> sanction("kill");
|
||||
}
|
||||
}
|
||||
}
|
||||
case "list_blocks":
|
||||
write(w("_PAGES_configure_user_block_head",
|
||||
([ "_title" : "Block Management",
|
||||
"_submit_value" : "Submit" ])));
|
||||
DAEMON_PATH "hosts"->list();
|
||||
return 1;
|
||||
case "user_password":
|
||||
s = w("_PAGES_configure_user_password",
|
||||
([ "_title" : "Reset Password",
|
||||
"_submit_value" : "Edit" ]));
|
||||
break;
|
||||
case "user_password_edit":
|
||||
{
|
||||
object o;
|
||||
|
||||
unless (o = find_person(query["nick"])) {
|
||||
unless (o = summon_person(query["nick"])) {
|
||||
s = w("_PAGES_configure_user_password_failure",
|
||||
([ "_title" : "Reset Password" ]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (o->isNewbie()) {
|
||||
destruct(o);
|
||||
s = w("_PAGES_configure_user_password_failure",
|
||||
([ "_title" : "Reset Password" ]));
|
||||
break;
|
||||
}
|
||||
|
||||
s = w("_PAGES_configure_user_password_edit",
|
||||
([ "_title" : "Reset Password",
|
||||
"_submit_value" : "Reset Password",
|
||||
"_nick" : query["nick"] ]));
|
||||
break;
|
||||
}
|
||||
case "user_password_save":
|
||||
{
|
||||
object o;
|
||||
|
||||
if (! query["password"] || strlen(query["password"]) <= 2) {
|
||||
s = w("_PAGES_configure_user_password_failure_bad",
|
||||
([ "_title" : "Reset Password" ]));
|
||||
break;
|
||||
}
|
||||
|
||||
unless (o = find_person(query["nick"])) {
|
||||
unless (o = summon_person(query["nick"])) {
|
||||
s = w("_PAGES_configure_user_password_failure",
|
||||
([ "_title" : "Reset Password" ]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (o->isNewbie()) {
|
||||
destruct(o);
|
||||
s = w("_PAGES_configure_user_password_failure",
|
||||
([ "_title" : "Reset Password" ]));
|
||||
break;
|
||||
}
|
||||
|
||||
o->vSet("password", query["password"]);
|
||||
o->save();
|
||||
|
||||
s = w("_PAGES_configure_user_password_save",
|
||||
([ "_title" : "Reset Password",
|
||||
"_nick" : query["nick"],
|
||||
"_password" : query["password"] ]));
|
||||
break;
|
||||
}
|
||||
case "basic_mgm":
|
||||
s = w("_PAGES_configure_basic",
|
||||
([ "_title" : "Basic Server Management" ]));
|
||||
break;
|
||||
case "restart":
|
||||
s = w("_PAGES_configure_head",
|
||||
([ "_title" : "Restart" ]));
|
||||
s += "<b>Your chatserver is being restarted.</b>";
|
||||
// write at the bottom wouldn't be called after shutdown, would it?
|
||||
write(s);
|
||||
shutdown();
|
||||
return 1;
|
||||
case "list_udp":
|
||||
{
|
||||
mapping ports;
|
||||
string port;
|
||||
|
||||
s = w("_PAGES_configure_basic_udp_head",
|
||||
([ "_title" : "List UDP Ports" ]));
|
||||
ports = DAEMON_PATH "udp"->listPorts(1);
|
||||
|
||||
foreach (port : m_indices(ports)) {
|
||||
s += w("_PAGES_configure_basic_udp_entry",
|
||||
ports[port]);
|
||||
}
|
||||
|
||||
s += w("_PAGES_configure_basic_udp_tail");
|
||||
|
||||
break;
|
||||
}
|
||||
case "room_mgm":
|
||||
s = w("_PAGES_configure_room",
|
||||
([ "_title" : "Room Management" ]));
|
||||
break;
|
||||
case "room_owned":
|
||||
s = w("_PAGES_configure_room_owned",
|
||||
([ "_title" : "Manage Owned Rooms",
|
||||
"_submit_value" : "Edit / Add" ]));
|
||||
break;
|
||||
case "room_owned_save":
|
||||
{
|
||||
mapping del;
|
||||
|
||||
del = ([ ]);
|
||||
|
||||
m_delete(query, "option");
|
||||
|
||||
if (query["delete"]) {
|
||||
rm("place/" + lower_case(query["NAME"]) + ".c");
|
||||
s = w("_PAGES_configure_room_deleted",
|
||||
([ "_title" : "Room Deleted",
|
||||
"_name" : query["NAME"] ]));
|
||||
break;
|
||||
}
|
||||
|
||||
if (query["ALLOW_EXTERNAL"]) {
|
||||
query["ALLOW_EXTERNAL"] = "";
|
||||
} else {
|
||||
del += ([ "ALLOW_EXTERNAL" ]);
|
||||
}
|
||||
|
||||
if (query["REGISTERED"]) {
|
||||
query["REGISTERED"] = "";
|
||||
} else {
|
||||
del += ([ "REGISTERED" ]);
|
||||
}
|
||||
|
||||
s = w("_PAGES_configure_head",
|
||||
([ "_title" : "Owned Room Management" ]));
|
||||
s += saveConfig("place/" + lower_case(query["NAME"]) + ".c", query, del);
|
||||
break;
|
||||
}
|
||||
case "room_owned_edit":
|
||||
{
|
||||
mapping rs;
|
||||
string name;
|
||||
mixed t;
|
||||
|
||||
rs = parseConfig("place/" + lower_case(query["NAME"]) + ".c");
|
||||
P2(("===> %O\n", rs))
|
||||
unless ((t = isRoomType("OWNED", rs)) == 1) {
|
||||
if (t != -1) {
|
||||
s = w("_PAGES_configure_room_error_type",
|
||||
([ "_title" : "Manage Owned Rooms",
|
||||
"_name" : query["NAME"],
|
||||
"_expected" : "Owned",
|
||||
"_type" : t
|
||||
]));
|
||||
} else {
|
||||
s = w("_PAGES_configure_room_error_type_undefined",
|
||||
([ "_title" : "Manage Owned Rooms",
|
||||
"_name" : query["NAME"],
|
||||
"_expected" : "Owned" ]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (rs["NAME"]) {
|
||||
name = replace(rs["NAME"], "\"", "");
|
||||
} else {
|
||||
name = query["NAME"] || "";
|
||||
}
|
||||
|
||||
|
||||
s = w("_PAGES_configure_room_owned_edit",
|
||||
([ "_title" : "Manage Owned Rooms",
|
||||
"_submit_value" : "Save",
|
||||
"_name" : name,
|
||||
"_registered" : member(rs, "REGISTERED") ? " checked" : "",
|
||||
"_owned" : replace(rs["OWNED"] || "", "\"", """),
|
||||
"_external" : member(rs, "ALLOW_EXTERNAL") ? " checked" : "" ]));
|
||||
break;
|
||||
}
|
||||
case "room_public":
|
||||
s = w("_PAGES_configure_room_public",
|
||||
([ "_title" : "Manage Public Rooms",
|
||||
"_submit_value" : "Edit / Add" ]));
|
||||
break;
|
||||
case "room_public_save":
|
||||
{
|
||||
mapping del;
|
||||
|
||||
del = ([ ]);
|
||||
|
||||
m_delete(query, "option");
|
||||
|
||||
if (query["delete"]) {
|
||||
rm("place/" + lower_case(query["NAME"]) + ".c");
|
||||
s = w("_PAGES_configure_room_deleted",
|
||||
([ "_title" : "Room Deleted",
|
||||
"_name" : query["NAME"] ]));
|
||||
break;
|
||||
}
|
||||
|
||||
if (query["HISTORY"]) {
|
||||
query["HISTORY"] = "";
|
||||
} else {
|
||||
del += ([ "HISTORY" ]);
|
||||
}
|
||||
|
||||
if (query["ALLOW_EXTERNAL"]) {
|
||||
query["ALLOW_EXTERNAL"] = "";
|
||||
} else {
|
||||
del += ([ "ALLOW_EXTERNAL" ]);
|
||||
}
|
||||
|
||||
if (query["REGISTERED"]) {
|
||||
query["REGISTERED"] = "";
|
||||
} else {
|
||||
del += ([ "REGISTERED" ]);
|
||||
}
|
||||
|
||||
s = w("_PAGES_configure_head",
|
||||
([ "_title" : "Public Room Management" ]));
|
||||
s += saveConfig("place/" + lower_case(query["NAME"]) + ".c", query, del);
|
||||
break;
|
||||
}
|
||||
case "room_public_edit":
|
||||
{
|
||||
mapping rs;
|
||||
string name;
|
||||
mixed t;
|
||||
|
||||
rs = parseConfig("place/" + lower_case(query["NAME"]) + ".c");
|
||||
P2(("===> %O\n", rs))
|
||||
unless (intp(t = isRoomType("PUBLIC", rs))) {
|
||||
s = w("_PAGES_configure_room_error_type",
|
||||
([ "_title" : "Manage Public Rooms",
|
||||
"_name" : query["NAME"],
|
||||
"_expected" : "Public",
|
||||
"_type" : t
|
||||
]));
|
||||
break;
|
||||
}
|
||||
|
||||
if (rs["NAME"]) {
|
||||
name = replace(rs["NAME"], "\"", "");
|
||||
} else {
|
||||
name = query["NAME"] || "";
|
||||
}
|
||||
|
||||
|
||||
s = w("_PAGES_configure_room_public_edit",
|
||||
([ "_title" : "Manage Public Rooms",
|
||||
"_submit_value" : "Save",
|
||||
"_name" : name,
|
||||
"_history" : member(rs, "HISTORY") ? " checked" : "",
|
||||
"_registered" : member(rs, "REGISTERED") ? " checked" : "",
|
||||
"_external" : member(rs, "ALLOW_EXTERNAL") ? " checked" : "" ]));
|
||||
break;
|
||||
}
|
||||
case "save_config":
|
||||
{
|
||||
|
||||
s = w("_PAGES_configure_head",
|
||||
([ "_title" : "Edit Config" ]));
|
||||
s += saveConfig(CONFIGFILE, query);
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
// was um alles in der welt soll das?
|
||||
case "set":
|
||||
|
||||
m_delete(query, "option");
|
||||
|
||||
break; // gehört da n break hin?
|
||||
#endif
|
||||
case "edit_config":
|
||||
{
|
||||
mapping cv;
|
||||
cv = parseConfig(CONFIGFILE);
|
||||
// sowas gehört in externe dateien.. am besten .fmt wegen
|
||||
// mehrsprachigkeit und layouting und template syntax und und..
|
||||
s = w("_PAGES_configure_head", ([ "_title" : "Edit Config" ]));
|
||||
|
||||
s += "<div align=\"center\" style=\"float:clear; text-align:center;\">\n"
|
||||
"<table bgcolor=\"#004411\" cellspacing=0 cellpadding=3>\n"
|
||||
"<form method=GET action=configure name=zero>\n"
|
||||
"<input type=hidden name=option value=\"save_config\">\n";
|
||||
|
||||
foreach(string key, string value : cv) {
|
||||
if (value) {
|
||||
value = replace(value, "\"", """);
|
||||
|
||||
s += "<tr><td style=\"border-left: 1px solid #f90; border-top: 1px solid #f90;\"><b>" + key + ":</b></td><td style=\"border-top: 1px solid #f90; border-right: 1px solid #f90;\"><input type=\"text\" value=\"" + value
|
||||
+ "\" name=\"" + key + "\"></td></tr>\n"
|
||||
"<tr><td colspan=2 style=\"padding-left:10px; border-bottom: 1px solid #fc0; border-right: 1px solid #f90; border-left: 3px solid #fc0;\">" + (description[key] || "") + "</td></tr>\n"
|
||||
"<tr><td><span style=\"font-size:1px;\"> </span></td></tr>\n";
|
||||
}
|
||||
}
|
||||
|
||||
s += "<tr><td colspan=2 align=center><p> </p>";
|
||||
s += w("_PAGES_configure_submit",
|
||||
([ "_submit_value" : "Save" ]));
|
||||
s += "</td></tr>\n"
|
||||
"</form></table>\n"
|
||||
"</div>\n";
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
s = w("_PAGES_configure_menu", ([ "_title" : "Menu" ]));
|
||||
}
|
||||
|
||||
write(s);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
htget(prot, query, headers, qs) {
|
||||
hterror(prot, 501, "This server hasn't enabled webbased administration");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
isRoomType(expected, mapping rs) {
|
||||
string type;
|
||||
|
||||
unless (sizeof(rs)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
foreach (type : filter(({ "OWNED", "MODERATED", "NEWSFEED_RSS",
|
||||
"SLAVE", "CONNECTED_IRC", "THREADS",
|
||||
"GAMESERV", "LINK", "PUBLIC" }),
|
||||
lambda( ({ 'x }), ({#'?, ({ #'!=, 'x, expected }) })) )) {
|
||||
if(member(rs, type))
|
||||
return type[0..0] + lower_case(type[1..]);
|
||||
}
|
||||
if (member(rs, expected)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
w(mc, mixed vars, bla) {
|
||||
if (bla) {
|
||||
vars = bla;
|
||||
}
|
||||
|
||||
if (mc == "_list_user_technical") {
|
||||
unless (mappingp(vars))
|
||||
vars = ([ ]);
|
||||
write(psyctext(T(mc, ""), vars));
|
||||
return;
|
||||
}
|
||||
|
||||
unless (mappingp(vars)) {
|
||||
return T(mc, "");
|
||||
}
|
||||
|
||||
return psyctext(T(mc, ""), vars);
|
||||
}
|
||||
|
||||
// only used for HOSTS_D
|
||||
pr(mc, text, vars) {
|
||||
string s, ip, reason;
|
||||
|
||||
// we'll keep it this way, yet
|
||||
switch (mc) {
|
||||
case "_list_hosts_disabled":
|
||||
s = "";
|
||||
foreach (ip, reason: vars) {
|
||||
s += w(mc,
|
||||
([ "_ip" : ip,
|
||||
"_reason" : reason ]));
|
||||
}
|
||||
}
|
||||
|
||||
write(s);
|
||||
}
|
||||
|
||||
#endif
|
154
world/net/http/edit.c
Normal file
154
world/net/http/edit.c
Normal file
|
@ -0,0 +1,154 @@
|
|||
// this code contributed from symlynX webchat. currently not in use.
|
||||
|
||||
#include <net.h>
|
||||
#include <text.h>
|
||||
#include <person.h>
|
||||
#include <ht/http.h>
|
||||
#include <url.h>
|
||||
|
||||
#define NO_INHERIT
|
||||
#include <user.h>
|
||||
#undef NO_INHERIT
|
||||
|
||||
// #define v(VAR) user->vQuery(VAR)
|
||||
|
||||
htget(prot, query, headers, qs) {
|
||||
string nick, lang, layout, token;
|
||||
mixed user;
|
||||
mapping _v, sups;
|
||||
int newbie;
|
||||
|
||||
P2(("edit query: %O\n", query))
|
||||
nick = query["user"];
|
||||
user = find_person(nick);
|
||||
token = query["token"];
|
||||
|
||||
lang = query["lang"];
|
||||
sTextPath(0, lang, "ht");
|
||||
|
||||
htok(prot);
|
||||
unless (nick && user && user->validToken(token)) {
|
||||
write( hthead("edit") +
|
||||
T("_PAGES_edit_invalid", "Who are you?<br>"));
|
||||
return 1;
|
||||
}
|
||||
// unless (newbie = user->isNewbie()) _v = user->vMapping();
|
||||
_v = user->vMapping() || ([]);
|
||||
unless (lang) lang = v("language");
|
||||
|
||||
//newbie = v("password") == 0;
|
||||
newbie = user->isNewbie();
|
||||
|
||||
if (v("name")) nick = v("name");
|
||||
sups = v("subscriptions") || ([]);
|
||||
|
||||
#define FORM_HIDDEN "\n\
|
||||
<input type=hidden name=user value=\""+nick+"\">\n\
|
||||
<input type=hidden name=token value=\""+token+"\">\n\
|
||||
<input type=hidden name=lang value=\""+lang+"\">\n\
|
||||
<input type=hidden name=layout value=\""+layout+"\">"
|
||||
|
||||
#define FORM_OPTS " name=f method=GET action=\"/"+layout+"/modify\""
|
||||
|
||||
#ifdef VOLATILE
|
||||
# define FORM_START "<form" FORM_OPTS
|
||||
# define FORM_PAGE "_PAGES_register_newsletter"
|
||||
#else
|
||||
# define FORM_START "<form target=cout_" CHATNAME FORM_OPTS
|
||||
# define FORM_PAGE newbie? "_PAGES_register_form": "_PAGES_edit_form"
|
||||
#endif
|
||||
// here comes the most obvious demonstration
|
||||
// of the necessity of the psyctext parser :)
|
||||
write(T("_SCRIPT_edit", 0)
|
||||
+ hthead(newbie? "register": "edit")
|
||||
+ psyctext(T(FORM_PAGE, 0), ([
|
||||
// "_FORM_start" : FORM_START ">" FORM_HIDDEN,
|
||||
// "_FORM_start_check_email" : FORM_START "\
|
||||
onSubmit=\"return checkEmail(f.email.value)\">" FORM_HIDDEN,
|
||||
"_FORM_start" : FORM_START "\
|
||||
onSubmit=\"return check(f)\">" FORM_HIDDEN,
|
||||
"_FORM_end" : "</form>",
|
||||
"_nick" : nick,
|
||||
"_EDIT_nick" : v("name") || nick,
|
||||
"_EDIT_nick_size" : strlen(v("name") || nick),
|
||||
"_EDIT_email" : v("email") || "",
|
||||
#if 1
|
||||
"_EDIT_subscription_events_weekly"
|
||||
: member(sups,"events-weekly")? "checked": "",
|
||||
"_EDIT_subscription_politik_digital"
|
||||
: member(sups,"poldi")? "checked": "",
|
||||
#ifdef VOLATILE
|
||||
"_EDIT_subscription_events" : "checked",
|
||||
#else
|
||||
"_EDIT_subscription_events" : newbie||member(sups,"events")?
|
||||
"checked": "",
|
||||
# ifdef NEWSTICKER
|
||||
"_EDIT_subscription_politik" : member(sups,"dpa-pl")? "checked": "",
|
||||
"_EDIT_subscription_wirtschaft" : member(sups,"dpa-wi")? "checked": "",
|
||||
"_EDIT_subscription_vermischtes": member(sups,"dpa-vm")? "checked": "",
|
||||
# endif
|
||||
#endif
|
||||
"_EDIT_place_home" : v("home") || "",
|
||||
"_EDIT_color" : v("color") || "",
|
||||
// no longer up to date here..
|
||||
// might not behave exactly as intended
|
||||
"_EDIT_checkbox_filter" : v("filter") == FILTER_STRANGERS ?
|
||||
"checked" : "",
|
||||
"_EDIT_checkbox_colors_ignored" : v("ignorecolors") ? "checked" : "",
|
||||
"_EDIT_checkbox_visibility" : v("visibility") == "off" ?
|
||||
"" : "checked",
|
||||
"_EDIT_action_speak" : v("speakaction") || "",
|
||||
"_EDIT_action_motto" : v("me") || "",
|
||||
"_EDIT_page_public" : v("publicpage") || "",
|
||||
"_EDIT_page_private" : v("privatepage") || "",
|
||||
"_EDIT_file_key_public" : v("keyfile") || "",
|
||||
"_EDIT_description_private" : v("privatetext") || "",
|
||||
"_EDIT_description_public" : v("publictext") || "",
|
||||
"_EDIT_description_preferences" : v("likestext") || "",
|
||||
"_EDIT_description_preferences_not" : v("dislikestext") || "",
|
||||
"_EDIT_favorite_animal" : v("animalfave") || "",
|
||||
"_EDIT_favorite_popstar" : v("popstarfave") || "",
|
||||
"_EDIT_favorite_music" : v("musicfave") || "",
|
||||
"_EDIT_page_start" : v("startpage") || "",
|
||||
#endif
|
||||
])
|
||||
));
|
||||
|
||||
write("<div class='roomsub'>Room Subscriptions<br/>\n");
|
||||
foreach(mixed key, mixed val : v("subscriptions")) {
|
||||
// note: the immediateness is not really used these days
|
||||
write("<div class='each'><a href='");
|
||||
unless(is_formal(key)) {
|
||||
write(query_server_unl() + "@" + key);
|
||||
} else {
|
||||
write(key);
|
||||
}
|
||||
write("'>" + key + "</a></div>\n");
|
||||
}
|
||||
write("</div>\n");
|
||||
|
||||
// build unified data structure for contacts
|
||||
mapping paliases = ([ ]);
|
||||
foreach(mixed key, mixed val : v("people")) {
|
||||
paliases[key] = ({ 0, val });
|
||||
}
|
||||
foreach(mixed key, mixed val : v("aliases")) {
|
||||
if (paliases[val])
|
||||
paliases[val][0] = key;
|
||||
else
|
||||
paliases[val] = ({ key, 0 });
|
||||
}
|
||||
|
||||
// make a link to a edit page for each contact?
|
||||
write("<div class='friends'>Friends<br/>\n");
|
||||
foreach(mixed key, mixed val : paliases) {
|
||||
// note: look at val to determine status
|
||||
write("<div class='each'><a href='" + key);
|
||||
write("'>" + (val[0] || key) + "</a>");
|
||||
if (val[1])
|
||||
write(sprintf("subscription state %O\n", val[1]));
|
||||
write("</div>\n");
|
||||
}
|
||||
write("</div>\n");
|
||||
return 1;
|
||||
}
|
29
world/net/http/examine.c
Normal file
29
world/net/http/examine.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
#include <net.h>
|
||||
#include <text.h>
|
||||
#include <person.h>
|
||||
|
||||
htget(prot, query, headers, qs) {
|
||||
string nick, t;
|
||||
object user;
|
||||
|
||||
htok3(prot, 0, "Expires: 0\n");
|
||||
if (nick = query["user"]) user = find_person(nick);
|
||||
unless (user) {
|
||||
// should be a different mc here..
|
||||
t = "_error_invalid_authentication_token";
|
||||
} else unless (user->validToken(query["token"])) {
|
||||
t = "_error_invalid_authentication_token";
|
||||
} else if ((t = query["cmd"]) && strlen(t)) {
|
||||
user->parsecmd(t); // htcmd?
|
||||
t = "_echo_execute_web";
|
||||
} else if (t = user->htDescription(prot, query, headers, qs, "")) {
|
||||
P4(("result: %O\n", t))
|
||||
write(t);
|
||||
return 1;
|
||||
}
|
||||
localize(query["lang"], "html");
|
||||
w("_HTML_head");
|
||||
w(t || "_failure_unavailable_description");
|
||||
w("_HTML_tail");
|
||||
return 1;
|
||||
}
|
214
world/net/http/fetch.c
Normal file
214
world/net/http/fetch.c
Normal file
|
@ -0,0 +1,214 @@
|
|||
// $Id: fetch.c,v 1.39 2008/04/09 08:29:37 lynx Exp $ // vim:syntax=lpc
|
||||
//
|
||||
// generic HTTP GET client, mostly used for RSS -
|
||||
// but we could fetch any page or data with it, really
|
||||
// tobij even made the object have the URL as its object name. fancy! ;)
|
||||
//
|
||||
#include <net.h>
|
||||
#include <ht/http.h>
|
||||
#include <url.h>
|
||||
#include <services.h>
|
||||
|
||||
virtual inherit NET_PATH "output"; // virtual: in case we get inherited..
|
||||
inherit NET_PATH "connect";
|
||||
//inherit NET_PATH "place/master";
|
||||
|
||||
#ifdef NEW_QUEUE
|
||||
inherit NET_PATH "queue2";
|
||||
#else
|
||||
inherit NET_PATH "queue";
|
||||
#endif
|
||||
|
||||
volatile mapping headers, fheaders;
|
||||
volatile string modificationtime, etag, http_message;
|
||||
volatile string useragent = SERVER_VERSION;
|
||||
volatile int http_status, port, fetching, ssl;
|
||||
volatile string buffer, thehost, url, fetched, host, resource;
|
||||
volatile string basicauth;
|
||||
|
||||
int parse_status(string all);
|
||||
int parse_header(string all);
|
||||
int buffer_content(string all);
|
||||
|
||||
string qHost() { return thehost; }
|
||||
|
||||
void fetch(string murl) {
|
||||
if (url) return;
|
||||
url = replace(murl, ":/", "://");
|
||||
P3(("%O: fetch(%O)\n", ME, url))
|
||||
connect();
|
||||
}
|
||||
|
||||
object load() { return ME; }
|
||||
|
||||
void setHTTPBasicAuth(string user, string password) {
|
||||
basicauth = "Authorization: Basic " + encode_base64(user + ":" + password) + "\r\n";
|
||||
}
|
||||
|
||||
string sAgent(string a) {
|
||||
PT(("sAgent(%O) in %O\n", a, ME))
|
||||
return useragent = a;
|
||||
}
|
||||
|
||||
// net/place/news code follows.
|
||||
|
||||
void connect() {
|
||||
mixed t;
|
||||
|
||||
fetching = 1;
|
||||
ssl = 0;
|
||||
unless (thehost) {
|
||||
unless (sscanf(url, "http%s://%s/%!s", t, thehost)) {
|
||||
P0(("%O couldn't parse %O\n", ME, url))
|
||||
return 0;
|
||||
}
|
||||
thehost = lower_case(thehost);
|
||||
ssl = t == "s";
|
||||
}
|
||||
P3(("URL, THEHOST: %O, %O\n", url, thehost))
|
||||
unless (port)
|
||||
unless (sscanf(thehost, "%s:%d", thehost, port) == 2)
|
||||
port = ssl? HTTPS_SERVICE: HTTP_SERVICE;
|
||||
P2(("Resolving %O and connecting.\n", thehost))
|
||||
::connect(thehost, port);
|
||||
}
|
||||
|
||||
varargs int real_logon(int arg) {
|
||||
string scheme;
|
||||
|
||||
headers = ([ ]);
|
||||
http_status = 500;
|
||||
http_message = "(failure)"; // used by debug only
|
||||
|
||||
unless(::logon(arg)) return -1;
|
||||
unless (url) return -3;
|
||||
unless (resource) sscanf(url, "%s://%s/%s", scheme, host, resource);
|
||||
|
||||
buffer = "";
|
||||
if (modificationtime)
|
||||
buffer += "If-Modified-Since: "+ modificationtime + "\r\n";
|
||||
if (useragent) buffer += "User-Agent: "+ useragent +"\r\n";
|
||||
//if (etag)
|
||||
// emit("If-None-Match: " + etag + "\r\n");
|
||||
// we won't need connection: close w/ http/1.0
|
||||
//emit("Connection: close\r\n\r\n");
|
||||
PT(("%O using %O\n", ME, buffer))
|
||||
emit("GET /"+ resource +" HTTP/1.0\r\n"
|
||||
"Host: "+ host +"\r\n"
|
||||
+ buffer +
|
||||
"\r\n");
|
||||
|
||||
buffer = "";
|
||||
next_input_to(#'parse_status);
|
||||
return 0; // duh.
|
||||
}
|
||||
|
||||
varargs int logon(int arg, int sub) {
|
||||
// when called from xmlrpc.c we can't do TLS anyway
|
||||
if (sub) return ::logon(arg);
|
||||
if (ssl) tls_init_connection(ME, #'real_logon);
|
||||
else real_logon(arg);
|
||||
return 0; // duh.
|
||||
}
|
||||
|
||||
int parse_status(string all) {
|
||||
string prot;
|
||||
string state;
|
||||
|
||||
sscanf(all, "%s%t%s", prot, state);
|
||||
sscanf(state, "%d%t%s", http_status, http_message);
|
||||
P3(("%O got %O %O from %O\n", ME, http_status, http_message, host));
|
||||
// P2(("http_status %O == %O?\n", http_status, R_OK))
|
||||
next_input_to(#'parse_header);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse_header(string all) {
|
||||
string key, val;
|
||||
D2(D("htroom::parse is: " + all + "\n");)
|
||||
// TODO: parse status code
|
||||
if (all != "") {
|
||||
if (sscanf(all, "%s:%1.0t%s", key, val) == 2) {
|
||||
headers[lower_case(key)] = val;
|
||||
// P2(("ht head: %O = %O\n", key, val))
|
||||
}
|
||||
next_input_to(#'parse_header);
|
||||
return 1;
|
||||
} else {
|
||||
// das wollen wir nur bei status 200
|
||||
next_input_to(#'buffer_content);
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int buffer_content(string all) {
|
||||
buffer += all + "\n";
|
||||
next_input_to(#'buffer_content);
|
||||
return 1;
|
||||
}
|
||||
|
||||
disconnected(remainder) {
|
||||
headers["_fetchtime"] = isotime(ctime(time()), 1);
|
||||
if (headers["last-modified"])
|
||||
modificationtime = headers["last-modified"];
|
||||
if (headers["etag"])
|
||||
etag = headers["etag"]; // heise does not work with etag
|
||||
|
||||
fetched = buffer;
|
||||
if (remainder) fetched += remainder;
|
||||
fheaders = headers;
|
||||
buffer = headers = 0;
|
||||
switch (http_status) {
|
||||
case R_OK:
|
||||
mixed *waiter;
|
||||
while (qSize(ME)) {
|
||||
waiter = shift(ME);
|
||||
funcall(waiter[0], fetched, waiter[1] ? fheaders : copy(fheaders));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
monitor_report("_error_unknown_method_HTTP",
|
||||
S("http/fetch'ing %O returned %O %O", url || ME,
|
||||
http_status, http_message));
|
||||
// fall thru
|
||||
case R_NOTMODIFIED:
|
||||
qDel(ME);
|
||||
qInit(ME, 150, 5);
|
||||
}
|
||||
|
||||
fetching = 0;
|
||||
return 1; // presume this disc was expected
|
||||
}
|
||||
|
||||
varargs string content(closure cb, int force, int willbehave) {
|
||||
if (cb) {
|
||||
if (fetched) {
|
||||
if (force) {
|
||||
funcall(cb, fetched, willbehave ? fheaders : copy(fheaders));
|
||||
}
|
||||
} else {
|
||||
enqueue(ME, ({ cb, willbehave }));
|
||||
}
|
||||
}
|
||||
return fetched;
|
||||
}
|
||||
|
||||
varargs mapping headers(int willbehave) {
|
||||
return willbehave ? fheaders : copy(fheaders);
|
||||
}
|
||||
|
||||
string qHeader(mixed key) {
|
||||
if (mappingp(fheaders)) return fheaders[key];
|
||||
return 0;
|
||||
}
|
||||
|
||||
varargs void refetch(closure cb, int willbehave) {
|
||||
enqueue(ME, ({ cb, willbehave }));
|
||||
unless (fetching) connect();
|
||||
}
|
||||
|
||||
protected create() {
|
||||
qCreate();
|
||||
qInit(ME, 150, 5);
|
||||
}
|
42
world/net/http/header.i
Normal file
42
world/net/http/header.i
Normal file
|
@ -0,0 +1,42 @@
|
|||
// vim:noexpandtab:syntax=lpc
|
||||
// $Id: header.i,v 1.5 2007/10/08 11:00:31 lynx Exp $
|
||||
|
||||
#include <ht/http.h>
|
||||
|
||||
volatile int headerDone = 0;
|
||||
|
||||
http_ok(string prot, string type, string extra) {
|
||||
string h;
|
||||
|
||||
// yes, this is compatible to pre-HTTP/1.0 browsers. sick, i know.
|
||||
if (!prot || headerDone++) return;
|
||||
|
||||
h = type || extra ? htheaders(type, extra) +"\n"
|
||||
: "Content-type: " DEFAULT_CONTENT_TYPE "\n\n";
|
||||
emit(HTTP_SVERS " 200 Sure\n"+ h);
|
||||
}
|
||||
|
||||
varargs http_error(string prot, int code, string comment, string html) {
|
||||
string out;
|
||||
|
||||
out = "<body text=white bgcolor=black link=green vlink=green>\n";
|
||||
if (html) out = sprintf("<title>%s</title>\n%s%s", comment, out, html);
|
||||
else out = sprintf("\
|
||||
<title>error %d</title>\n\
|
||||
%s\n\
|
||||
<table width=\"100%%\" height=\"90%%\"><tr><th><h1><br>\n\n\
|
||||
%s\n\n\
|
||||
</h1></th></tr></table>\n\
|
||||
",
|
||||
code, out, comment
|
||||
);
|
||||
// <a href=\"mailto:%s?subject=%s\">%s</a>\n
|
||||
//, WEBMASTER_EMAIL, comment, WEBMASTER_EMAIL
|
||||
|
||||
// yes, this is compatible to pre-HTTP/1.0 browsers. sick, i know.
|
||||
if (!headerDone++ && prot) {
|
||||
// I used to output the comment, but Id have to cut out the
|
||||
// newline from the db
|
||||
emit(sprintf(HTTP_SVERS " 200 Actually %03d but MSIE steals my error page\n%s\n%s", code, htheaders(), out));
|
||||
} else emit(out);
|
||||
}
|
178
world/net/http/library.i
Normal file
178
world/net/http/library.i
Normal file
|
@ -0,0 +1,178 @@
|
|||
// vim:noexpandtab:syntax=lpc
|
||||
// $Id: library.i,v 1.38 2008/04/08 23:12:16 lynx Exp $
|
||||
//
|
||||
// HTTP function library -lynx
|
||||
//
|
||||
// (extension to "simul_efun")
|
||||
|
||||
#include <net.h>
|
||||
#include <services.h>
|
||||
|
||||
#include "driver.h"
|
||||
//#include CONFIG_PATH "ports.h"
|
||||
#include "ht/http.h"
|
||||
|
||||
#if !HAS_PORT(HTTP_PORT, HTTP_PATH)
|
||||
# undef HTTP_PORT
|
||||
# define HTTP_PORT 44444 // should return null instead?
|
||||
#endif
|
||||
|
||||
// not worthy of summoning url.h for this one..
|
||||
string htuniform(object server, string prot, mapping headers) {
|
||||
// it is really totally crazy to trust what the browser says
|
||||
string host = headers["host"];
|
||||
int port = HTTP_PORT;
|
||||
#if __EFUN_DEFINED__(tls_query_connection_state)
|
||||
#ifndef HTTPS_HOST
|
||||
string scheme = "http://";
|
||||
# endif
|
||||
unless (server) server = this_interactive();
|
||||
if (tls_query_connection_state(server)) {
|
||||
#ifdef HTTPS_HOST
|
||||
return HTTPS_HOST;
|
||||
#else
|
||||
scheme = "https://";
|
||||
# if HAS_TLS_PORT(HTTPS_PORT)
|
||||
port = HTTPS_PORT;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
# define SCHEME scheme
|
||||
# define PORT port
|
||||
#else
|
||||
# define SCHEME "http://"
|
||||
# define PORT HTTP_PORT
|
||||
#endif
|
||||
unless (host) {
|
||||
#ifdef HTTP_HOST
|
||||
return HTTP_HOST;
|
||||
#else
|
||||
host = SERVER_HOST;
|
||||
// HTTP_SERVICE is 80 from services.h
|
||||
if (port != HTTP_SERVICE) host += ":"+to_string(port);
|
||||
#endif
|
||||
}
|
||||
return SCHEME + host;
|
||||
}
|
||||
|
||||
varargs string htheaders(string type, string extra) {
|
||||
string out;
|
||||
|
||||
unless (stringp(type)) type = DEFAULT_CONTENT_TYPE;
|
||||
out = "Content-type: "+ type +"\n";
|
||||
|
||||
// if (length) {
|
||||
// printf("Content-length: %d\n", length);
|
||||
// }
|
||||
|
||||
if (extra) out += extra;
|
||||
return out;
|
||||
}
|
||||
|
||||
varargs string htheaders2(string type, string extra) {
|
||||
return htheaders(type, extra)
|
||||
+ "Server: " HTTP_SERVER "\nDate: "+ ctime(time()) +"\n";
|
||||
}
|
||||
|
||||
void htrequireauth(string prot, string type, string realm) {
|
||||
if (prot) write(HTTP_SVERS + " " + to_string(R_UNAUTHORIZED) +
|
||||
"Your password, please\n");
|
||||
if (type == "digest") {
|
||||
write("WWW-Authenticate: Digest realm=\"" + realm +
|
||||
"\", nonce=\"" + time() + "\"\n");
|
||||
} else {
|
||||
write("WWW-Authenticate: Basic realm=\"" + realm + "\"\n");
|
||||
}
|
||||
}
|
||||
|
||||
varargs string htredirect(string prot, string target, string comment, int permanent) {
|
||||
if (!comment) comment = "Check this out";
|
||||
if (!target) target = "/";
|
||||
|
||||
if (prot) {
|
||||
printf("%s %d %s\n%s", HTTP_SVERS,
|
||||
permanent ? R_MOVED : R_FOUND, comment, htheaders());
|
||||
}
|
||||
printf("\
|
||||
Location: %s\n\
|
||||
\n\
|
||||
<a href=\"%s\">%s</a>.\n\
|
||||
",
|
||||
target, target, comment);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// written and donated by _Marcus_
|
||||
//
|
||||
// thanx!!
|
||||
|
||||
/* convert %XX escapes to real chars */
|
||||
static int xx2l(string str) {
|
||||
int x;
|
||||
|
||||
str=lower_case(str);
|
||||
if (str[0]>='0' && str[0]<='9') x=(str[0]-'0')*16;
|
||||
if (str[0]>='a' && str[0]<='f') x=(str[0]-'a'+10)*16;
|
||||
if (str[1]>='0' && str[1]<='9') x+=str[1]-'0';
|
||||
if (str[1]>='a' && str[1]<='f') x+=str[1]-'a'+10;
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Content-Encoding: url-encoded */
|
||||
string urldecode(string txt) {
|
||||
string *xx;
|
||||
int i;
|
||||
|
||||
txt=implode(explode(txt,"+")," ");
|
||||
#if __EFUN_DEFINED__(regexplode)
|
||||
xx=regexplode(txt,"%..");
|
||||
for (i=1;i<sizeof(xx)-1;i+=2)
|
||||
xx[i]=sprintf("%c",xx2l(xx[i][1..]));
|
||||
txt=implode(xx,"");
|
||||
#endif
|
||||
return txt;
|
||||
}
|
||||
|
||||
#ifndef DEFAULT_HT_TYPE
|
||||
# define DEFAULT_HT_TYPE "text/plain"
|
||||
#endif
|
||||
string content_type(string suffix) {
|
||||
switch(lower_case(suffix)) {
|
||||
case "html":
|
||||
return "text/html";
|
||||
case "xml":
|
||||
//return "application/xml";
|
||||
return "text/xml"; // what type is to be used here?
|
||||
case "bz2":
|
||||
return "application/x-bzip2";
|
||||
case "class":
|
||||
return "application/octet-stream";
|
||||
case "css":
|
||||
return "text/css";
|
||||
case "gif":
|
||||
return "image/gif";
|
||||
case "gz":
|
||||
return "application/x-gzip";
|
||||
case "jpeg":
|
||||
case "jpg":
|
||||
return "image/jpeg";
|
||||
case "js":
|
||||
return "application/x-javascript";
|
||||
case "pdf":
|
||||
return "application/pdf";
|
||||
case "png":
|
||||
return "image/png";
|
||||
case "ps":
|
||||
case "eps":
|
||||
return "application/postscript";
|
||||
case "tar":
|
||||
return "application/tar";
|
||||
case "zip":
|
||||
return "application/zip";
|
||||
case "swf":
|
||||
return "application/x-shockwave-flash";
|
||||
default:
|
||||
return DEFAULT_HT_TYPE;
|
||||
}
|
||||
return 0;
|
||||
}
|
26
world/net/http/login.c
Normal file
26
world/net/http/login.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include <net.h>
|
||||
#include <text.h>
|
||||
#include <person.h>
|
||||
|
||||
htget(prot, query, headers, qs) {
|
||||
string nick, t;
|
||||
object user;
|
||||
|
||||
if (nick = query["user"]) user = find_person(nick);
|
||||
unless (user) {
|
||||
// should be a different mc here..
|
||||
t = "_error_invalid_authentication_token";
|
||||
} else unless (user->validToken(query["token"])) {
|
||||
t = "_error_invalid_authentication_token";
|
||||
} else {
|
||||
PT(("replacing cookie %O\n", headers["cookie"]))
|
||||
htok3(prot, 0, "Set-Cookie: psyced=\""+ qs +"\";\n");
|
||||
t = "_PAGES_login";
|
||||
}
|
||||
htok3(prot, 0, "Expires: 0\n");
|
||||
localize(query["lang"], "html");
|
||||
w("_HTML_head");
|
||||
w(t);
|
||||
w("_HTML_tail");
|
||||
return 1;
|
||||
}
|
140
world/net/http/modify.c
Normal file
140
world/net/http/modify.c
Normal file
|
@ -0,0 +1,140 @@
|
|||
// this code contributed from symlynX webchat. currently not in use.
|
||||
|
||||
#include <net.h>
|
||||
#include <text.h>
|
||||
#include <ht/html.h>
|
||||
#include <ht/http.h>
|
||||
#include <person.h>
|
||||
|
||||
volatile string nick;
|
||||
volatile mixed user;
|
||||
|
||||
htget(prot, query, headers, qs) {
|
||||
string key, value, k;
|
||||
int okay;
|
||||
|
||||
P2(("\n\nQuery: %O\n", query))
|
||||
nick = query["user"];
|
||||
localize(query["lang"], "ht");
|
||||
|
||||
htok(prot);
|
||||
write (hthead("modifying "+nick+"'s settings") + htfs_on "<th>");
|
||||
unless (nick) {
|
||||
write( T("_PAGES_register_nickless", "Who are you?")
|
||||
+ htfs_off);
|
||||
return 1;
|
||||
}
|
||||
unless (user = find_person(nick)) {
|
||||
write( T("_PAGES_register_offline",
|
||||
"You're not in the chat?<br>Please enter it.")
|
||||
+ T("_HTML_back", "") + htfs_off );
|
||||
return 1;
|
||||
}
|
||||
unless (user -> validToken(query["token"])) {
|
||||
write( T("_error_invalid_authentication_token",
|
||||
"Invalid token. Please log in anew.")
|
||||
+ htfs_off);
|
||||
return 1;
|
||||
}
|
||||
okay = 1;
|
||||
|
||||
// endlich mal hier verallgemeinern. damn! TODO
|
||||
#ifdef NEWSTICKER
|
||||
user->subscribe(member(query, "sub-events") ? SUBSCRIBE_TEMPORARY : SUBSCRIBE_NOT, "events", 1);
|
||||
user->subscribe(member(query, "sub-events-weekly") ? SUBSCRIBE_TEMPORARY : SUBSCRIBE_NOT, "events-weekly", 1);
|
||||
#endif
|
||||
// sonderfall wegen logischer inversion :(
|
||||
key = "visibility";
|
||||
user -> vSet(key, query[key] || "off");
|
||||
|
||||
unless (query["colors"]) user -> vDel("ignorecolors");
|
||||
unless (query["filter"]) user -> vDel("filter");
|
||||
|
||||
// statt einzelauswertung sollte man einen _request_store
|
||||
// erzeugen ähnlich zu den vCards die jabber clients
|
||||
// schicken.
|
||||
//
|
||||
foreach (key : query) switch(k = lower_case(key)) {
|
||||
case "sub-poldi":
|
||||
case "sub-events":
|
||||
case "sub-events-weekly":
|
||||
case "sub-dpa-PL":
|
||||
case "sub-dpa-WI":
|
||||
case "sub-dpa-VM":
|
||||
case "opass":
|
||||
case "pass":
|
||||
case "pass2":
|
||||
case "token":
|
||||
case "layout":
|
||||
case "user":
|
||||
case "lang": // should this be renamed to "language" ??
|
||||
case "x":
|
||||
case "y":
|
||||
case "visibility":
|
||||
break;
|
||||
case "me":
|
||||
value = query[key];
|
||||
if (!value || value == "" || value == "-")
|
||||
user->vDel(k);
|
||||
else user->vSet(k, value);
|
||||
break;
|
||||
default:
|
||||
// if (trail("text", k)) {
|
||||
// // catch CR?
|
||||
// }
|
||||
value = query[key];
|
||||
// D("checking ("+key+", "+value+")\n");
|
||||
if (user -> checkVar(&k, &value)) {
|
||||
// D("valid as "+value+"\n");
|
||||
if (!value || value == "" || value == "-")
|
||||
user->vDel(k);
|
||||
else user->vSet(k, value);
|
||||
} else okay = 0;
|
||||
}
|
||||
#ifndef VOLATILE
|
||||
okay = okay && changePassword(query);
|
||||
#endif
|
||||
if (okay) {
|
||||
#ifndef VOLATILE
|
||||
user -> save();
|
||||
#else
|
||||
log_file("NEWSLETTER", "[%s] %O %O\n\n",
|
||||
ctime(), query_ip_name(), query);
|
||||
#endif
|
||||
write( T("_PAGES_edit_stored",
|
||||
"Settings successfully stored.")
|
||||
+ T("_HTML_back", "") + htfs_off );
|
||||
} else
|
||||
write( T("_HTML_back", "") + htfs_off );
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef VOLATILE
|
||||
static changePassword(query) {
|
||||
string pw;
|
||||
string* t;
|
||||
|
||||
pw = query["pass"];
|
||||
unless (pw && pw != "") return 1;
|
||||
|
||||
if (t = legal_password(pw, nick)) {
|
||||
write( T(t[0],t[1]) );
|
||||
return 0;
|
||||
}
|
||||
if (pw != query["pass2"]) {
|
||||
write( T("_error_invalid_password_repetition",
|
||||
"Sorry, but the repetition does not match the password.<br>Please check.") );
|
||||
return 0;
|
||||
}
|
||||
if (user ->checkPassword(query["opass"])) {
|
||||
string token;
|
||||
|
||||
user->vSet("password", pw);
|
||||
} else {
|
||||
printf( T("_error_invalid_password",
|
||||
"You provided an invalid password, %s."), nick );
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
11
world/net/http/myVideo.swf.c
Normal file
11
world/net/http/myVideo.swf.c
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <net.h>
|
||||
#include <text.h>
|
||||
#include <ht/http.h>
|
||||
|
||||
// phone call thing. we need to pass the query data to a flash film
|
||||
// but we don't have any flash film yet. TODO
|
||||
//
|
||||
htget(prot, query, headers, qs) {
|
||||
htredirect(prot, "/static/myVideo.swf", "stupid flash film", 0);
|
||||
return 1;
|
||||
}
|
212
world/net/http/profile.c
Normal file
212
world/net/http/profile.c
Normal file
|
@ -0,0 +1,212 @@
|
|||
// $Id: profile.c,v 1.2 2007/04/11 13:48:57 lynx Exp $ vim:syntax=lpc
|
||||
//
|
||||
// <kuchn> profile.c, a web based user settings/profile changer,
|
||||
// called from net/http/server.
|
||||
//
|
||||
// TODO: please make use of the new convert_profile(vars, 0, "set") and
|
||||
// convert_profile(settings, "set", 0) to convert a mapping of settings
|
||||
// into a mapping of PSYC variables and back. this should make a lot of
|
||||
// code in here unnecessary. avoiding replication is g00000d.
|
||||
//
|
||||
// i'm unhappy with the way of authing.. first i thought this could be
|
||||
// inherited somehow to be a part of the user object, but thats schmarn.
|
||||
// but i think psyc auth would be a nice way here..
|
||||
// using checkPassword() the way you do is fine! we are not planning
|
||||
// to use a web-based editor for remote PSYC items.. and the
|
||||
// asynchronicity of it isn't something HTTP can easily handle.
|
||||
// HTTP isn't as cool as PSYC you know? hahahahahahahahahahah
|
||||
|
||||
// as long as this is in development it could cause security breaches
|
||||
// in production servers. so please only use this on experimental servers.
|
||||
#ifdef EXPERIMENTAL
|
||||
|
||||
#include <net.h>
|
||||
#include <text.h>
|
||||
#include <person.h>
|
||||
|
||||
object user;
|
||||
|
||||
create() {
|
||||
sTextPath(0, 0, "html");
|
||||
}
|
||||
|
||||
htget(prot, query, headers, qs) {
|
||||
htok3(prot, "text/html", "Cache-Control: no-cache\n");
|
||||
w("_PAGES_user_header");
|
||||
|
||||
auth(prot, query, headers, qs);
|
||||
}
|
||||
|
||||
checkAuth(val, prot, query, headers, qs, user) {
|
||||
if(! val)
|
||||
{
|
||||
w("_PAGES_user_login_failed");
|
||||
return;
|
||||
}
|
||||
|
||||
w("_PAGES_user_header");
|
||||
|
||||
switch(query["action"]) {
|
||||
case "settings":
|
||||
if(query["set"] == "1")
|
||||
settings(prot, query, headers, qs, user);
|
||||
else
|
||||
w("_PAGES_user_settings_body", ([
|
||||
"_username" : query["username"],
|
||||
"_password" : query["password"],
|
||||
|
||||
"_speakaction" : user->v("speakaction") ? user->v("speakaction") : "",
|
||||
"_commandcharacter" : user->v("commandcharacter") ? user->v("commandcharacter") : ""
|
||||
]) );
|
||||
break;
|
||||
case "profile":
|
||||
if(query["set"] == "1")
|
||||
profile(prot, query, headers, qs, user);
|
||||
else
|
||||
w("_PAGES_user_profile_body", ([
|
||||
"_username" : query["username"],
|
||||
"_password" : query["password"],
|
||||
|
||||
"_me" : user->v("me") ? user->v("me") : "",
|
||||
"_publicpage" : user->v("publicpage") ? user->v("publicpage") : "",
|
||||
"_publictext" : user->v("publictext") ? user->v("publictext") : "",
|
||||
"_publicname" : user->v("publicname") ? user->v("publicname") : "",
|
||||
"_animalfave" : user->v("animalfave") ? user->v("animalfave") : "",
|
||||
"_popstarfave" : user->v("popstarfave") ? user->v("popstarfave") : "",
|
||||
"_musicfave" : user->v("musicfave") ? user->v("musicfave") : "",
|
||||
"_privatetext" : user->v("privatetext") ? user->v("privatetext") : "",
|
||||
"_likestext" : user->v("likestext") ? user->v("likestext") : "",
|
||||
"_dislikestext" : user->v("dislikestext") ? user->v("dislikestext") : "",
|
||||
"_privatepage" : user->v("privatepage") ? user->v("privatepage") : "",
|
||||
"_email" : user->v("email") ? user->v("email") : "",
|
||||
"_color" : user->v("color") ? user->v("color") : "",
|
||||
"_language" : user->v("language") ? user->v("language") : "",
|
||||
"_telephone" : user->v("telephone") ? user->v("telephone") : ""
|
||||
]) );
|
||||
break;
|
||||
default:
|
||||
w("_PAGES_user_index", ([ "_username" : query["username"], "_password" : query["password"] ]));
|
||||
break;
|
||||
}
|
||||
|
||||
w("_PAGES_user_footer");
|
||||
}
|
||||
|
||||
auth(prot, query, headers, qs) {
|
||||
if(! stringp(query["username"]) || ! stringp(query["password"]))
|
||||
{
|
||||
w("_PAGES_user_login_body");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(query["username"] == "" || query["password"] == "")
|
||||
{
|
||||
w("_PAGES_user_login_empty");
|
||||
return 0;
|
||||
}
|
||||
|
||||
user = summon_person(query["username"]);
|
||||
if(!user || user->isNewbie())
|
||||
{
|
||||
w("_PAGES_user_login_notregistered");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ok = 1;
|
||||
user->checkPassword(query["password"], "plain", "", "", #'checkAuth, prot, query, headers, qs, user);
|
||||
}
|
||||
|
||||
settings(prot, query, headers, qs, user) {
|
||||
foreach(string k, string v : query) {
|
||||
int ok = 0;
|
||||
|
||||
switch(k) {
|
||||
case "password":
|
||||
ok = 1;
|
||||
break;
|
||||
case "speakaction":
|
||||
ok = 1;
|
||||
break;
|
||||
case "commandcharacter":
|
||||
ok = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if(! ok)
|
||||
continue;
|
||||
|
||||
if(v == "")
|
||||
{
|
||||
//if(v != "password")
|
||||
// user->vDel(k);
|
||||
// do nothing? maybe every setting is needed.. then this would be bad.
|
||||
}
|
||||
else
|
||||
user->vSet(k, v); // password won't be set? humm.
|
||||
}
|
||||
|
||||
w("_PAGES_user_settings_changed", ([ "_username" : query["username"], "_password" : query["password"] ]) );
|
||||
}
|
||||
|
||||
profile(prot, query, headers, qs, user) {
|
||||
foreach(string k, string v : query) {
|
||||
int ok = 0;
|
||||
|
||||
switch(k)
|
||||
{
|
||||
case "me":
|
||||
ok = 1;
|
||||
break;
|
||||
case "publicpage":
|
||||
ok = 1;
|
||||
break;
|
||||
case "publictext":
|
||||
ok = 1;
|
||||
break;
|
||||
case "publicname":
|
||||
ok = 1;
|
||||
break;
|
||||
case "animalfave":
|
||||
ok = 1;
|
||||
break;
|
||||
case "popstarfave":
|
||||
ok = 1;
|
||||
break;
|
||||
case "musicfave":
|
||||
ok = 1;
|
||||
break;
|
||||
case "privatetext":
|
||||
ok = 1;
|
||||
break;
|
||||
case "likestext":
|
||||
ok = 1;
|
||||
break;
|
||||
case "dislikestext":
|
||||
ok = 1;
|
||||
break;
|
||||
case "privatepage":
|
||||
ok = 1;
|
||||
break;
|
||||
case "email":
|
||||
ok = 1;
|
||||
break;
|
||||
case "telephone":
|
||||
ok = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if(! ok)
|
||||
continue;
|
||||
|
||||
if(v == "")
|
||||
user->vDel(k);
|
||||
else
|
||||
user->vSet(k, v);
|
||||
}
|
||||
|
||||
w("_PAGES_user_profile_changed", ([ "_username" : query["username"], "_password" : query["password"] ]) );
|
||||
}
|
||||
|
||||
w(mc, vars) { write(psyctext(T(mc, ""), vars)); }
|
||||
|
||||
#endif
|
76
world/net/http/register.c
Normal file
76
world/net/http/register.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
// this code contributed from symlynX webchat. currently not in use.
|
||||
|
||||
#include <net.h>
|
||||
#include <text.h>
|
||||
#include <person.h>
|
||||
|
||||
htget(prot, query, headers, qs) {
|
||||
string nick, pw, email, lang, layout;
|
||||
mixed user;
|
||||
array(string) t;
|
||||
|
||||
if (mappingp(query)) {
|
||||
nick = query["user"];
|
||||
email = query["email"];
|
||||
pw = query["pass", 0];
|
||||
lang = query["lang", 0];
|
||||
}
|
||||
sTextPath(0, lang, "ht");
|
||||
|
||||
htok(prot);
|
||||
unless (nick) {
|
||||
printf(hthead("register") + T("_PAGES_register_nickless",
|
||||
"Who are you?<br>"));
|
||||
return 1;
|
||||
}
|
||||
if (!pw || pw == "" && !email) {
|
||||
write( hthead("register") + psyctext(
|
||||
T("_PAGES_register_form", 0), ([
|
||||
"_nick": nick,
|
||||
"_FORM_start": "\
|
||||
<form name=f method=GET action=\""+object2url(ME)+"\">\n\
|
||||
<input type=hidden name=user value=\""+nick+"\">\n\
|
||||
<input type=hidden name=lang value=\""+lang+"\">\n\
|
||||
<input type=hidden name=layout value=\""+layout+"\">",
|
||||
"_EDIT_email": email || "",
|
||||
"_EDIT_subscription_politik": "checked",
|
||||
"_EDIT_subscription_wirtschaft": "checked",
|
||||
"_EDIT_subscription_vermischtes": "checked",
|
||||
"_FORM_end": "</form>",
|
||||
]) ));
|
||||
return 1;
|
||||
}
|
||||
if (t = legal_password(pw, nick)) {
|
||||
write(hthead("illegal password") +
|
||||
T(t[0],t[1]) + T("_HTML_back", "") );
|
||||
return 1;
|
||||
}
|
||||
if (pw != query["pass2"]) {
|
||||
write(hthead("mistyped") +
|
||||
T("_error_invalid_password_repetition",
|
||||
"Sorry, but the repetition does not match the password. Please check.") +
|
||||
T("_HTML_back", "") );
|
||||
return 1;
|
||||
}
|
||||
unless (user = find_person(nick)) {
|
||||
write(hthead("register") +
|
||||
T("_PAGES_register_offline",
|
||||
"You're not in the chat?<br>Please enter it.\n"));
|
||||
return 1;
|
||||
}
|
||||
if (user ->checkPassword()) {
|
||||
string token;
|
||||
|
||||
user->vSet("password", pw);
|
||||
if (email) user->vSet("email", email);
|
||||
#ifdef NEWSTICKER
|
||||
user->subscribe(!member(query, "sub-dpa-PL"), "dpa-PL", 1);
|
||||
user->subscribe(!member(query, "sub-dpa-WI"), "dpa-WI", 1);
|
||||
user->subscribe(!member(query, "sub-dpa-VM"), "dpa-VM", 1);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
write( hthead("register") + T("_PAGES_register_taken",
|
||||
"This nickname is already registered."));
|
||||
return 1;
|
||||
}
|
235
world/net/http/server.c
Normal file
235
world/net/http/server.c
Normal file
|
@ -0,0 +1,235 @@
|
|||
// $Id: server.c,v 1.58 2008/03/11 13:42:25 lynx Exp $ // vim:syntax=lpc
|
||||
//
|
||||
// yes, psyced is also a web server, like every decent piece of code. ;)
|
||||
//
|
||||
#include <net.h>
|
||||
#include <server.h>
|
||||
#include <text.h>
|
||||
|
||||
#include "header.i"
|
||||
|
||||
volatile string url, file, qs, version;
|
||||
volatile mapping headers;
|
||||
|
||||
// we're using #'closures to point to the functions we're giving the
|
||||
// next_input_to(). as i don't want to restructure the whole file, i need
|
||||
// to predefine some functions.
|
||||
//
|
||||
// quite stupid indeed, as they don't got any modifiers or whatever :)
|
||||
parse_url(input);
|
||||
parse_header(input);
|
||||
devNull();
|
||||
|
||||
qScheme() { return "none"; }
|
||||
|
||||
logon() {
|
||||
D2(D("»»» New SmallHTTP user\n");)
|
||||
|
||||
// bigger buffer (for psyc logo)
|
||||
set_buffer_size(32768);
|
||||
// unfortunately limited to a compilation limit
|
||||
// so we would have to push large files in chunks
|
||||
// using heart_beat() or something like that TODO
|
||||
|
||||
next_input_to(#'parse_url);
|
||||
call_out(#'quit, TIME_LOGIN_IDLE);
|
||||
}
|
||||
|
||||
disconnected(remainder) {
|
||||
// TODO: shouldn't ignore remainder
|
||||
D2(D("««« SmallHTTP got disconnected.\n");)
|
||||
destruct(ME);
|
||||
return 1; // expected death of socket
|
||||
}
|
||||
|
||||
// gets called from async apps
|
||||
done() { quit(); }
|
||||
|
||||
#if DEBUG > 1
|
||||
quit() {
|
||||
D2(D("««« SmallHTTP user done.\n");)
|
||||
::quit();
|
||||
}
|
||||
#endif
|
||||
|
||||
void create() {
|
||||
if (clonep(ME)) headers = ([ ]);
|
||||
}
|
||||
|
||||
parse_wait(null) { // waiting to send my error message here
|
||||
if (null == "") {
|
||||
http_error("HTTP/1.0", 405, "Invalid Request (Welcome Proxyscanner)");
|
||||
quit();
|
||||
}
|
||||
next_input_to(#'parse_wait);
|
||||
}
|
||||
|
||||
parse_url(input) {
|
||||
P3(("=== SmallHTTP got: %O\n", input))
|
||||
unless (sscanf(input, "GET%t%s%tHTTP/%s", url, version)) {
|
||||
if (sscanf(input, "CONNECT%t%~s")) {
|
||||
next_input_to(#'parse_wait);
|
||||
return;
|
||||
} else {
|
||||
quit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
version = "HTTP/" + version;
|
||||
|
||||
P2(("=== SmallHTTP user requested url: %O\n", url))
|
||||
next_input_to(#'parse_header);
|
||||
}
|
||||
|
||||
parse_header(input) {
|
||||
string key, val;
|
||||
|
||||
P4((input + "\n"))
|
||||
|
||||
unless (input == "") {
|
||||
if (sscanf(input, "%s:%1.0t%s", key, val)) {
|
||||
headers[lower_case(key)] = val;
|
||||
}
|
||||
|
||||
next_input_to(#'parse_header);
|
||||
} else {
|
||||
process();
|
||||
next_input_to(#'devNull);
|
||||
}
|
||||
}
|
||||
|
||||
parse_query(query, qs) {
|
||||
foreach (string pair : explode(qs, "&")) {
|
||||
string key, val;
|
||||
|
||||
if (sscanf(pair, "%s=%s", key, val)) {
|
||||
P3(("query: pair: %s, %s\n", urldecode(key),
|
||||
urldecode(val)))
|
||||
query[urldecode(key)] = urldecode(val);
|
||||
} else {
|
||||
P3(("query: single: %s\n", urldecode(pair)))
|
||||
query[urldecode(pair)] = 1;
|
||||
}
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
process() {
|
||||
string t, ext;
|
||||
mapping query = ([]);
|
||||
object o;
|
||||
int done = 1;
|
||||
|
||||
// take defaults from cookie, then override by query string
|
||||
t = headers["cookie"];
|
||||
P4(("found cookie: %O\n", t))
|
||||
if (t && sscanf(t, "psyced=\"%s\"", t)) {
|
||||
P3(("got cookie: %O\n", t))
|
||||
query = parse_query(query, t);
|
||||
P4(("parsed cookie: %O\n", query))
|
||||
}
|
||||
if (sscanf(url, "%s?%s", file, qs)) {
|
||||
P3(("got query: %O\n", qs))
|
||||
query = parse_query(query, qs);
|
||||
} else {
|
||||
file = url;
|
||||
}
|
||||
P4(("parsed query: %O\n", query))
|
||||
switch (file) {
|
||||
case "/favicon.ico":
|
||||
#if 0
|
||||
htredirect(version, "http://www.psyced.org/favicon.ico",
|
||||
"This one looks neat", 1);
|
||||
quit();
|
||||
return 1;
|
||||
#else
|
||||
file = "/static/favicon.ico";
|
||||
break;
|
||||
#endif
|
||||
case "/":
|
||||
case "":
|
||||
// should we look for text/wml in the accept: and go directly
|
||||
// to /net/wap/index ?
|
||||
//
|
||||
http_ok(version);
|
||||
sTextPath(0, query["lang"], "html");
|
||||
write( //T("_HTML_head", "<title>" CHATNAME "</title><body>\n"
|
||||
// "<center><table width=404><tr><td>") +
|
||||
T("_PAGES_index", "<i><a href=\"http://www.psyc.eu\"><img src="
|
||||
"\"static/psyc.gif\" width=464 height=93 border=0></a><p>"
|
||||
"<a href=\"http://www.psyced.org\">psyced</a></i> -"
|
||||
" your multicast capable web application server.") );
|
||||
// T("_HTML_tail", "</td></tr></table></center></body>"));
|
||||
quit();
|
||||
return 1;
|
||||
case "/static": // really don't like to do this, but the IE stores directories
|
||||
// (history) without trailing slash, even if the url originaly
|
||||
// has one, at least IIRC.
|
||||
htredirect(version, "/static/", "use the trailing slash", 1);
|
||||
quit();
|
||||
return 1;
|
||||
case "/static/":
|
||||
file = "/static/index.html";
|
||||
break;
|
||||
}
|
||||
switch (file[1]) {
|
||||
case '~':
|
||||
if (o = summon_person(file[2..], NET_PATH "user")) {
|
||||
o->htinfo(version, query, headers, qs);
|
||||
}
|
||||
quit();
|
||||
return 1;
|
||||
case '@':
|
||||
file = PLACE_PATH+ lower_case(file[2..]);
|
||||
break;
|
||||
default:
|
||||
if (abbrev("/static/", file)) {
|
||||
if (file_size(file) > 0) {
|
||||
if (sscanf(file, "%!s.%s", ext)) {
|
||||
while (sscanf(ext, "%!s.%s", ext)) ;
|
||||
}
|
||||
http_ok(version, content_type(ext), 0);
|
||||
binary_message(read_file(file));
|
||||
quit();
|
||||
return 1;
|
||||
}
|
||||
} else if (sscanf(file, "/%s/%s.page", ext, t) == 2) {
|
||||
http_ok(version);
|
||||
sTextPath(0, query["lang"] || ext, "html");
|
||||
t = replace(t, "/", "_");
|
||||
write(T("_HTML_head", "<title>" CHATNAME "</title><body>\n"
|
||||
"<center><table width=404><tr><td>") +
|
||||
T("_PAGES_"+t, "[no such page]\n") +
|
||||
T("_HTML_tail", "</td></tr></table></center></body>"));
|
||||
quit();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (index(file, ':') != -1) {
|
||||
http_error(version, 501, "Not Implemented. Whatever you are trying "
|
||||
"there, this server won't help you.");
|
||||
quit();
|
||||
return;
|
||||
}
|
||||
|
||||
o = file -> load();
|
||||
if (objectp(o) || o = find_object(file))
|
||||
done = o->htget(version, query, headers, qs) != HTMORE;
|
||||
|
||||
if (done)
|
||||
quit();
|
||||
else
|
||||
remove_call_out(#'quit);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// wozu binary_message nochmal durch eine funktion jagen? lieber so nennen:
|
||||
emit(a) { return binary_message(a); }
|
||||
|
||||
devNull() {
|
||||
next_input_to(#'devNull);
|
||||
|
||||
D2(D("=== SmallHTTP just ignored some input\n");)
|
||||
}
|
167
world/net/http/userconfigure.c
Normal file
167
world/net/http/userconfigure.c
Normal file
|
@ -0,0 +1,167 @@
|
|||
//
|
||||
// <kuchn> additional user modules putted into net/user/ (initial revision):
|
||||
// configure.c, a web based user settings/profile changer, called by net/http
|
||||
//
|
||||
// i'm unhappy with the way of authing.. first i thought this could be inheriated somehow to be a part of the user object, but thats schmarn.
|
||||
// but i think psyc auth would be a nice way here..
|
||||
//
|
||||
|
||||
#include <net.h>
|
||||
#include <text.h>
|
||||
#include <person.h>
|
||||
|
||||
create() {
|
||||
sTextPath(0, 0, "html");
|
||||
}
|
||||
|
||||
htget(prot, query, headers, qs) {
|
||||
htok3(prot, "text/html", "Cache-Control: no-cache\n");
|
||||
w("_PAGES_user_header");
|
||||
|
||||
unless(auth(prot, query, headers, qs))
|
||||
{
|
||||
w("_PAGES_user_footer");
|
||||
write("PROB");
|
||||
}
|
||||
}
|
||||
|
||||
checkAuth(val, prot, query, headers, qs, user) {
|
||||
unless(val) {
|
||||
w("_PAGES_user_login_failed");
|
||||
w("_PAGES_user_footer");
|
||||
return;
|
||||
}
|
||||
|
||||
switch(query["action"]) {
|
||||
case "settings":
|
||||
if(query["set"] == "1")
|
||||
settings(prot, query, headers, qs, user);
|
||||
else
|
||||
w("_PAGES_user_settings_body", ([
|
||||
"_username" : query["username"],
|
||||
"_password" : query["password"],
|
||||
|
||||
"_speakaction" : user->vQuery("speakaction") || "",
|
||||
"_commandcharacter" : user->vQuery("commandcharacter") || ""
|
||||
]) );
|
||||
break;
|
||||
case "profile":
|
||||
if(query["set"] == "1")
|
||||
profile(prot, query, headers, qs, user);
|
||||
else
|
||||
w("_PAGES_user_profile_body", ([
|
||||
"_username" : query["username"],
|
||||
"_password" : query["password"],
|
||||
|
||||
"_me" : user->vQuery("me") || "",
|
||||
"_publicpage" : user->vQuery("publicpage") || "",
|
||||
"_publictext" : user->vQuery("publictext") || "",
|
||||
"_publicname" : user->vQuery("publicname") || "",
|
||||
"_animalfave" : user->vQuery("animalfave") || "",
|
||||
"_popstarfave" : user->vQuery("popstarfave") || "",
|
||||
"_musicfave" : user->vQuery("musicfave") || "",
|
||||
"_privatetext" : user->vQuery("privatetext") || "",
|
||||
"_likestext" : user->vQuery("likestext") || "",
|
||||
"_dislikestext" : user->vQuery("dislikestext") || "",
|
||||
"_privatepage" : user->vQuery("privatepage") || "",
|
||||
"_email" : user->vQuery("email") || "",
|
||||
"_color" : user->vQuery("color") || "",
|
||||
"_language" : user->vQuery("language") || "",
|
||||
"_telephone" : user->vQuery("telephone") || ""
|
||||
]) );
|
||||
break;
|
||||
default:
|
||||
w("_PAGES_user_index", ([ "_username" : query["username"], "_password" : query["password"] ]));
|
||||
break;
|
||||
}
|
||||
|
||||
w("_PAGES_user_footer");
|
||||
}
|
||||
|
||||
auth(prot, query, headers, qs) {
|
||||
if(! stringp(query["username"]) || ! stringp(query["password"]))
|
||||
{
|
||||
w("_PAGES_user_login_body");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(query["username"] == "" || query["password"] == "")
|
||||
{
|
||||
w("_PAGES_user_login_empty");
|
||||
return 0;
|
||||
}
|
||||
|
||||
object user = summon_person(query["username"]);
|
||||
if(! user || user->isNewbie())
|
||||
{
|
||||
w("_PAGES_user_login_notregistered");
|
||||
return 0;
|
||||
}
|
||||
|
||||
user->checkPassword(query["password"], "plain", "", "", #'checkAuth, prot, query, headers, qs, user);
|
||||
return 1;
|
||||
}
|
||||
|
||||
settings(prot, query, headers, qs, user) {
|
||||
foreach(string k, string v : query) {
|
||||
int ok = 0;
|
||||
|
||||
switch(k) {
|
||||
case "password":
|
||||
case "speakaction":
|
||||
case "commandcharacter":
|
||||
ok = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if(! ok)
|
||||
continue;
|
||||
|
||||
if(v == "")
|
||||
{
|
||||
if(k == "speakaction")
|
||||
user->vDel(k);
|
||||
}
|
||||
else
|
||||
user->vSet(k, v); // password won't be set? humm.
|
||||
}
|
||||
|
||||
w("_PAGES_user_settings_changed", ([ "_username" : query["username"], "_password" : query["password"] ]) );
|
||||
}
|
||||
|
||||
profile(prot, query, headers, qs, user) {
|
||||
foreach(string k, string v : query) {
|
||||
int ok = 0;
|
||||
|
||||
switch(k)
|
||||
{
|
||||
case "me":
|
||||
case "publicpage":
|
||||
case "publictext":
|
||||
case "publicname":
|
||||
case "animalfave":
|
||||
case "popstarfave":
|
||||
case "musicfave":
|
||||
case "privatetext":
|
||||
case "likestext":
|
||||
case "dislikestext":
|
||||
case "privatepage":
|
||||
case "email":
|
||||
case "telephone":
|
||||
ok = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if(! ok)
|
||||
continue;
|
||||
|
||||
if(v == "")
|
||||
user->vDel(k);
|
||||
else
|
||||
user->vSet(k, v);
|
||||
}
|
||||
|
||||
w("_PAGES_user_profile_changed", ([ "_username" : query["username"], "_password" : query["password"] ]) );
|
||||
}
|
||||
|
||||
w(mc, vars) { write(psyctext(T(mc, ""), vars)); }
|
296
world/net/http/xmlrpc.c
Normal file
296
world/net/http/xmlrpc.c
Normal file
|
@ -0,0 +1,296 @@
|
|||
// $Id: xmlrpc.c,v 1.23 2008/03/11 13:42:26 lynx Exp $ // vim:syntax=lpc
|
||||
//
|
||||
// TODO: shares to much code with url fetcher
|
||||
// in the ideal world this would only contain marshal/unmarshal code
|
||||
// for xmlrpc
|
||||
// possibly we can come up with an marshal/unmarshal api and use
|
||||
// the same framework for xml-rpc, soap and other things
|
||||
//
|
||||
#include <net.h>
|
||||
#include <ht/http.h>
|
||||
#include <url.h>
|
||||
#include <xml.h>
|
||||
|
||||
#include <lpctypes.h>
|
||||
|
||||
virtual inherit NET_PATH "output"; // virtual: in case we get inherited..
|
||||
inherit NET_PATH "http/fetch";
|
||||
inherit NET_PATH "xml/parse";
|
||||
|
||||
volatile string postbody;
|
||||
volatile closure callback;
|
||||
|
||||
int parse_status(string all);
|
||||
int parse_header(string all);
|
||||
int buffer_content(string all);
|
||||
|
||||
// recursively dump a structure
|
||||
dump(mixed value) {
|
||||
/* TODO: what happens if we feed a recursive structure here? */
|
||||
string t;
|
||||
switch(typeof(value)) {
|
||||
case T_NUMBER:
|
||||
return sprintf("<value><int>%d</int></value>", value);
|
||||
case T_FLOAT:
|
||||
return sprintf("<value><double>%O</double></value>", value);
|
||||
case T_STRING:
|
||||
// in theory we would have to convert this to utf-8!
|
||||
// must to encode '<' and '&'
|
||||
return sprintf("<value><string>%s</string></value>", value);
|
||||
case T_MAPPING: // -> struct
|
||||
// NOTE: THIS DOES NOT SUPPORT mappings with m_width > 2
|
||||
t = "<value><struct>\n";
|
||||
foreach(string key, mixed val : value) {
|
||||
t += sprintf("<member>\n"
|
||||
"<name>%s</name>\n"
|
||||
"%s\n"
|
||||
"</member>\n",
|
||||
key, dump(val));
|
||||
}
|
||||
t += "</struct></value>";
|
||||
return t;
|
||||
case T_POINTER: // array
|
||||
t = "<value><array><data>\n";
|
||||
foreach(mixed val : value) {
|
||||
t += dump(val) + "\n";
|
||||
}
|
||||
t += "</data></array></value>";
|
||||
return t;
|
||||
default:
|
||||
PT(("do not know how to serialize %O type %d\n", value, typeof(value)))
|
||||
PT(("yes, this is a bug!\n"))
|
||||
break;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
marshal(params) {
|
||||
string s = "<params>\n";
|
||||
foreach(mixed param : params) {
|
||||
s += sprintf("<param>\n%s\n</param>\n", dump(param));
|
||||
}
|
||||
return s + "</params>\n";
|
||||
}
|
||||
|
||||
void fetch(string murl) {
|
||||
if (url) return;
|
||||
url = murl;
|
||||
}
|
||||
|
||||
void request(string method, mixed params, closure cb) { // TODO: errback API
|
||||
if (fetching) {
|
||||
enqueue(ME, ({ method, params, cb }));
|
||||
return;
|
||||
}
|
||||
callback = cb;
|
||||
postbody = sprintf("<?xml version='1.0'?>\n"
|
||||
"<methodCall>\n"
|
||||
"<methodName>%s</methodName>\n"
|
||||
"%s\n"
|
||||
// last is a \r\n!
|
||||
"</methodCall>\r\n", method, marshal(params));
|
||||
P3(("%O: request(%O)\n", ME, url))
|
||||
connect();
|
||||
}
|
||||
|
||||
int logon(int arg) {
|
||||
buffer = "";
|
||||
httpheaders = ([ ]);
|
||||
http_status = 500;
|
||||
|
||||
// this is all not https: compatible..
|
||||
unless(::logon(arg, 1)) return -1;
|
||||
unless (url) return -3;
|
||||
unless (resource) sscanf(url, "http://%s/%s", host, resource);
|
||||
// do somthing
|
||||
emit("POST /" + resource + " HTTP/1.0\r\n"
|
||||
+ "Host: " + host + "\r\n"
|
||||
+ "Content-Type: text/xml\r\n"
|
||||
+ "Content-Length: " + sizeof(postbody) + "\r\n");
|
||||
emit("\r\n");
|
||||
//+ "User-Agent: " + SERVER_VERSION + "\r\n");
|
||||
emit(postbody);
|
||||
next_input_to(#'parse_status);
|
||||
return 0; // duh.
|
||||
}
|
||||
|
||||
mixed * innerMarshal(mixed val) {
|
||||
mixed args;
|
||||
string type;
|
||||
// TODO: methodSignature behaves strangely
|
||||
XMLNode value;
|
||||
foreach(mixed key, mixed vval : val) {
|
||||
if (stringp(key) && key[0] == '/') {
|
||||
type = key[1..];
|
||||
value = val[key];
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch(type) {
|
||||
case "boolean": // map to 0, 1
|
||||
// should probably check if this string is really "0" or "1"
|
||||
case "int":
|
||||
return ({ to_int(value[Cdata]) });
|
||||
case "double":
|
||||
// sigh... this is not double
|
||||
return ({ to_float(value[Cdata]) });
|
||||
case "dateTime.iso8601": // uhm... what do we map this to?
|
||||
// unix timestamp probably?
|
||||
break;
|
||||
case "base64":
|
||||
// probably containing binary data
|
||||
return ({ decode_base64(value[Cdata]) });
|
||||
// these two are complicated
|
||||
case "array":
|
||||
args = ({ });
|
||||
value = value["/data"]["/value"];
|
||||
unless(nodelistp(value)) value = ({ value });
|
||||
foreach(mixed v : value) {
|
||||
args += innerMarshal(v);
|
||||
}
|
||||
return ({ args });
|
||||
case "struct": // mapping
|
||||
args = ([ ]);
|
||||
unless(nodelistp(value["/member"]))
|
||||
value["/member"] = ({ value["/member"] });
|
||||
foreach(mixed v: value["/member"]) {
|
||||
args[v["/name"][Cdata]] = innerMarshal(v["/value"])[0];
|
||||
}
|
||||
return ({ args });
|
||||
case "fault": // something is wrong
|
||||
break;
|
||||
default: // if no type is indicated, the type is string
|
||||
case "string": // utf-8 encoded!
|
||||
return ({ value[Cdata] });
|
||||
}
|
||||
return ({ });
|
||||
}
|
||||
|
||||
mixed unMarshal(XMLNode parsed) {
|
||||
XMLNode params;
|
||||
mixed *helper;
|
||||
|
||||
mixed args = ({ }); // could be pre-allocated
|
||||
unless(parsed["/fault"]) {
|
||||
if (parsed["/params"]) {
|
||||
params = parsed["/params"]["/param"];
|
||||
} else {
|
||||
params = ({ });
|
||||
}
|
||||
unless(nodelistp(params)) params = ({ params }); // special case
|
||||
foreach(mixed param : params) {
|
||||
args += innerMarshal(param["/value"]);
|
||||
}
|
||||
// should probably watch for HTTP 200
|
||||
return args;
|
||||
} else {
|
||||
// TODO: fault handling
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void disconnected(remainder) {
|
||||
mixed *args;
|
||||
|
||||
httpheaders["_fetchtime"] = isotime(ctime(time()), 1);
|
||||
if (httpheaders["last-modified"])
|
||||
modificationtime = httpheaders["last-modified"];
|
||||
if (httpheaders["etag"])
|
||||
etag = httpheaders["etag"]; // heise does not work with etag
|
||||
|
||||
fetched = buffer;
|
||||
fheaders = httpheaders;
|
||||
buffer = httpheaders = 0;
|
||||
fetching = 0;
|
||||
if (pointerp(args)) // no fault
|
||||
funcall(callback, args...);
|
||||
|
||||
if (qSize(ME)) {
|
||||
args = shift(ME);
|
||||
call_out(#'request, 0, args...); // at next heart_beat
|
||||
// request(args...);
|
||||
}
|
||||
return 1; // kind of expected
|
||||
}
|
||||
|
||||
// helper methods, useful at least for ORA meerkat
|
||||
// could do caching for these things
|
||||
void listMethods(closure cb) {
|
||||
request("system.listMethods", ({ }), cb);
|
||||
}
|
||||
|
||||
void methodHelp(string method, closure cb) {
|
||||
request("system.methodHelp", ({ method }), cb);
|
||||
}
|
||||
|
||||
void methodSignature(string method, closure cb) {
|
||||
request("system.methodSignature", ({ method }), cb);
|
||||
}
|
||||
|
||||
|
||||
varargs string content(closure cb, int force, int willbehave) { return ""; } // makes no sense
|
||||
|
||||
create() {
|
||||
qCreate();
|
||||
qInit(ME, 150, 5);
|
||||
#ifdef MODULE_TESTS
|
||||
selftest();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
* MODULE TESTS
|
||||
* you should run them whenever you change the code
|
||||
* if they fail, debug!
|
||||
* do not check in code that does not pass the tests
|
||||
*--------------------------------------------------------------------*/
|
||||
#ifdef MODULE_TESTS
|
||||
// automatic test cases
|
||||
// add some if you like
|
||||
selftest() {
|
||||
// self tests...
|
||||
// be careful, the order for structs is not guaranteed
|
||||
int i, result;
|
||||
mixed *structures = ({
|
||||
({ 1, 2, 3, 4 }),
|
||||
// ({ (["a" : 1, "b" : "boo" ]) }),
|
||||
({ 1, 1.5, "a", ({ 1 }), (["a" : "foo" ]) })
|
||||
});
|
||||
mixed *strings = ({
|
||||
"<params>\n<param>\n<value><int>1</int></value>\n</param>\n<param>\n<value><int>2</int></value>\n</param>\n<param>\n<value><int>3</int></value>\n</param>\n<param>\n<value><int>4</int></value>\n</param>\n</params>\n",
|
||||
|
||||
// "<params>\n<param>\n<value><struct>\n<member>\n<name>a</name>\n<value><int>1</int></value>\n</member>\n<member>\n<name>b</name>\n<value><string>boo</string></value>\n</member>\n</struct></value>\n</param>\n</params>\n",
|
||||
|
||||
"<params>\n<param>\n<value><int>1</int></value>\n</param>\n<param>\n<value><double>1.5</double></value>\n</param>\n<param>\n<value><string>a</string></value>\n</param>\n<param>\n<value><array><data>\n<value><int>1</int></value>\n</data></array></value>\n</param>\n<param>\n<value><struct>\n<member>\n<name>a</name>\n<value><string>foo</string></value>\n</member>\n</struct></value>\n</param>\n</params>\n"
|
||||
});
|
||||
|
||||
i = 0;
|
||||
foreach(mixed test : structures) {
|
||||
result = marshal(test) == strings[i];
|
||||
if (result) {
|
||||
PT(("passed marshal test %d\n", i))
|
||||
} else {
|
||||
PT(("marshal test %d failed\n", i))
|
||||
PT(("%O\n%O\n", marshal(test), strings[i]))
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
i = 0;
|
||||
foreach(mixed test : strings) {
|
||||
// set callback internally! it is safe to do so as we are
|
||||
// doing only synchronus operations
|
||||
XMLNode x = new_XMLNode;
|
||||
x["/params"] = xmlparse(test);
|
||||
result = sprintf("%O", unMarshal(x)) == sprintf("%O", structures[i]);
|
||||
if (result) {
|
||||
PT(("passed unmarshal test %d\n", i))
|
||||
} else {
|
||||
PT(("unmarshal test %d failed\n", i))
|
||||
PT(("%O\n%O\n", unMarshal(x), structures[i]))
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue