/* Do not remove the headers from this file! see /USAGE for more info. */ /* ** file.c -- handler for I3's "file" service ** ** 950126, Deathblade: created */ #include <log.h> void oob_register_requests(mapping requests); void oob_register_replies(mapping replies); void oob_initiate_connection(string target_mudname); void oob_svc_send(object socket, mixed * message); void oob_svc_error(object socket, string errcode, string errmsg, mixed * errpacket); /* ** Store the lists of requests for each target mud */ nosave private mapping file_requests = ([ ]); nosave private string * file_status = ({ "request failed (write permission)", "request failed (read permission)", "request failed (fpath error)", "request failed (unknown error)", "request successful" }); private nomask string prepare_path(string path) { if ( path == "/" ) path = DIR_I3_FILES; else { string * parts; parts = explode(path, "/") - ({ "", "." }); for ( int idx = 0; idx < sizeof(parts); ) { if ( parts[idx] == ".." ) { if ( idx ) { parts[idx-1..idx] = ({ }); --idx; } else parts[idx..idx] = ({ }); } ++idx; } path = DIR_I3_FILES; if ( sizeof(parts) ) path += "/" + implode(parts, "/"); } DBBUG(path); return path; } private nomask void file_add_request(string mudname, mixed * request) { if ( !file_requests[mudname] ) file_requests[mudname] = request; else file_requests[mudname] += request; } nomask void do_file_list_request(string mudname, string dir) { file_add_request(mudname, ({ ({ "file-list-req", mud_name(), this_user()->query_userid(), dir, }) })); oob_initiate_connection(mudname); } nomask void do_file_put_request(string mudname, string local_fname, string remote_fname) { file_add_request(mudname, ({ ({ "file-put", random(50000), mud_name(), this_user()->query_userid(), remote_fname, local_fname, }) })); oob_initiate_connection(mudname); } nomask void do_file_get_request(string mudname, string local_fname, string remote_fname) { file_add_request(mudname, ({ ({ "file-get-req", random(50000), mud_name(), this_user()->query_userid(), remote_fname, local_fname, }) })); oob_initiate_connection(mudname); } private nomask mixed * handle_file_reply(string mudname, object socket, mixed * message, string request_type, string reply_type, int request_id, int reply_id, int req_user_idx ) { object p; mixed * requests = file_requests[mudname]; mixed * request; if ( !sizeof(requests) || requests[0][0] != request_type ) { oob_svc_error(socket, "bad-proto", "unexpected " + reply_type, message); return 0; } request = requests[0]; file_requests[mudname] = requests[1..]; if ( request[request_id] != message[reply_id] ) { oob_svc_error(socket, "bad-proto", reply_type + " did not match the " + request_type, message); return 0; } p = find_user(request[req_user_idx]); return ({ p, request }); } private nomask void handle_file_list_req(string mudname, object socket, mixed * message) { string dir; mixed * data; string err; dir = message[3]; if ( !sizeof(dir) || !stringp(dir) ) { oob_svc_error(socket, "bad-proto", "bad directory specified", message); return; } dir = prepare_path(dir); err = catch(data = get_dir(dir + "/*", -1)); if ( err ) { oob_svc_error(socket, "bad-directory", err, ({ })); return; } oob_svc_send(socket, ({ "file-list-reply", message[2], data })); } private nomask void handle_file_list_reply(string mudname, object socket, mixed * message) { mixed * info = handle_file_reply(mudname, socket, message, "file-list-req", "file-list-reply", 2, 1, 2); string list; if ( !info || !info[0] ) return; if ( message[2] ) { list = implode(message[2], (: sprintf("%s%-20s %8s %s\n", $1, $2[0], $2[1] == -2 ? "- DIR -" : ""+$2[1], ctime($2[2])) :), ""); } else { list = "<< an error occurred on the target mud >>\n"; } info[0]->receive_private_msg(sprintf("\nDirectory %s on %s:\n%s\n", info[1][3], mudname, list)); } private nomask void handle_file_put(string mudname, object socket, mixed * message) { string fname; string err; fname = message[4]; if ( !sizeof(fname) || !stringp(fname) ) { oob_svc_send(socket, ({ "file-put-ack", message[1], -1 })); return; } fname = prepare_path(fname); err = catch(write_file(fname, message[5], 1)); if ( err ) { oob_svc_send(socket, ({ "file-put-ack", message[1], 0 })); return; } oob_svc_send(socket, ({ "file-put-ack", message[1], 1 })); } private nomask void handle_file_put_ack(string mudname, object socket, mixed * message) { mixed * info = handle_file_reply(mudname, socket, message, "file-put", "file-put-ack", 1, 1, 3); string msg; int status; if ( !info || !info[0] ) return; status = message[2]; if ( status < -3 || status > 1 ) status = 3; else status += 3; msg = sprintf("\n[IFTP] %s put of %s: %s\n", mudname, info[1][5], file_status[status]); info[0]->receive_private_msg(msg); } private nomask void handle_file_get_req(string mudname, object socket, mixed * message) { string fname; string err; string contents; fname = message[4]; if ( !sizeof(fname) || !stringp(fname) ) { oob_svc_send(socket, ({ "file-get-reply", message[1], -1, 0 })); return; } fname = prepare_path(fname); err = catch(contents = read_file(fname)); if ( err ) { oob_svc_send(socket, ({ "file-get-reply", message[1], 0, 0 })); return; } oob_svc_send(socket, ({ "file-get-reply", message[1], 1, contents })); } private nomask void handle_file_get_reply(string mudname, object socket, mixed * message) { mixed * info = handle_file_reply(mudname, socket, message, "file-get-req", "file-get-reply", 1, 1, 3); string msg; int status; if ( !info ) return; status = message[2]; if ( status < -3 || status > 1 ) status = 3; else status += 3; msg = sprintf("\n[IFTP] %s get of %s (to %s): %s\n", mudname, info[1][4], info[1][5], file_status[status]); if ( status == 4 ) { string err; err = catch(write_file(info[1][5], message[3], 1)); if ( err ) msg = sprintf("\n[IFTP] %s get of %s: ERROR: %s\n", mudname, info[1][5], err); } if ( info[0] ) info[0]->receive_private_msg(msg); } protected nomask int file_has_outgoing(string mudname) { return sizeof(file_requests[mudname]) != 0; } protected nomask int file_send_outgoing(string mudname, object socket) { mixed * requests = file_requests[mudname]; mixed * request; if ( !sizeof(requests) ) return 0; request = requests[0]; switch ( request[0] ) { case "file-list-req": oob_svc_send(socket, request); break; case "file-put": oob_svc_send(socket, request[0..4] + ({ read_file(request[5]) })); break; case "file-get-req": oob_svc_send(socket, request[0..4]); break; } } protected nomask void file_startup() { oob_register_requests(([ "file-list-req" : (: handle_file_list_req :), "file-put" : (: handle_file_put :), "file-get-req" : (: handle_file_get_req :), ])); oob_register_replies(([ "file-list-reply" : (: handle_file_list_reply :), "file-put-ack" : (: handle_file_put_ack :), "file-get-reply" : (: handle_file_get_reply :), ])); }