//
// File : /adm/daemons/finger.c
//
// An improved interface to provide the information required by the "finger"
// command, as well as other essential information about the user, that may
// not be available when they are not logged in.
//
// This version of the finger daemon was written by Buddha@TMI-2, with some
// existing code from the old finger daemon (most of which he also did).
// This is part of the TMI-2 distribution mudlib.
// Please retain this header.
//
// Bug - bad argument 1 to extract() line 133
// possibly caused by someone being half logged in
// Mobydick thinks he fixed this bug, hasn't had the chance to test it.
// 2-15-93.
// Watcher eliminated references to users when the user is inhabiting a
// monster body (3/22/93)
// Watcher added in wizard label to specific user finger (4/3/93)
// Made to respect invisible status by Spock @ TMI-2 4/4/93
// Watcher rewrote the invisible checks to use the visible() efun, added
// the checks to the finger_all function, and added an alphabetic sort on
// the general finger output, 4/25/93.
//
// I fixed a problem where this_player() was used, and the call was
// from a remote mud. It might be broken on more places, but if
// the logs won't mind, i won't bother for now. Leto 011895
#include <uid.h>
#include <config.h>
#include <mudlib.h>
#include <login_macros.h>
#include <daemons.h>
#include <mailer.h>
inherit DAEMON;
#define LINE1 \
"=+=--=+=--=+=--=+=--=+=--=--=+=--=+=--=+=--=+=--=+=--=+=--=+=--=+=--=+=--=+=\n"
#define LINE2 \
"----------------------------------------------------------------------------\n"
// prototypes for local functions
string finger_group(string group);
int filter_users(object who);
mapping groups;
void create() {
seteuid(ROOT_UID);
}
// This function is called to restore the user's connection object that
// holds the essential login information. If the user in question is
// currently logged in, then their current connection object is returned,
// otherwise it is restored. You should probably call clean_up() on the
// object when finished, and it will either self-destruct, if not interactive
// or associated to a body, or save and wait for further information
// requests, if it is.
object restore_data(string name) {
object link;
if (find_player(name) && interactive(find_player(name))) {
return (object)find_player(name)->query_link();
}
link = new(CONNECTION);
seteuid(name);
export_uid(link);
seteuid(ROOT_UID);
link->set("name", name);
if (link->restore()) {
return link;
}
// If this fails, then let's clean up afterwards...
link->remove();
// Some names like .foo weren't getting away.
if(link) destruct(link);
if(link) log_file("fingerdest",sprintf("Connection of %s not dested by finger daemon, on %s.\n", name, ctime(time())));
return 0;
}
string finger_user(string who) {
object link;
mixed tmp1, tmp2, tmp3, tmp4, tmp5;
string msg;
mapping mail_stat;
int hibernate;
link = restore_data(who);
if (!link) {
if (sscanf(who, "(%s)", who))
return finger_group(who);
return "Finger: There is no such user.\n";
}
tmp1 = "Login name: " + who;
tmp2 = "In real life: ";
if (tmp3 = (string)link->RNAME)
tmp2 += extract(tmp3, 0, 22);
else
tmp2 += "?";
tmp4 = DOMAIN_D->query_domain(link);
tmp5 = DOMAIN_D->query_domain_level(link);
if ((tmp4 == 0) || (tmp4 == ""))
tmp4 = "None";
tmp4 = "Domain: " + tmp4 + " (" + tmp5 + ")";
msg = sprintf("%-38s%-38s\n", tmp1, tmp2);
tmp1 = user_path(who);
if (file_size(tmp1) == -1)
tmp1 = "(none)";
msg += sprintf("%-38s%-38s\n", "Directory: " + tmp1, tmp4);
msg += "Status: ";
if (adminp((string)link->query("name")))
msg += "Admin\n";
else if (link->query("wizard"))
msg += "Wizard\n";
else
msg += "Player\n";
tmp1 = find_player(who);
hibernate = (int)link->query("hibernate");
if (hibernate && time() < hibernate)
msg += "\n\t[In hibernation until " + ctime(hibernate) + "]\n\n";
if (tmp1) {
if (!filter_users(tmp1))
tmp1 = 0;
}
if (!link->query("last_on"))
msg += (tmp1 ? "On since: " : "Last on: ") + "Unavailable\n";
else
msg += ((tmp1 && !tmp1->query("npc")) ? "On since: " : "Last on: ") +
ctime((int)link->query("last_on")) + " from " +
(string)link->query("ip") + " \n";
if (tmp1) {
tmp1 = query_idle_string(tmp1, 1);
if (strlen(tmp1) > 0)
msg += tmp1 + "\n";
}
mail_stat = (mapping)MAILBOX_D->mail_status(who);
if (mail_stat["unread"])
msg += sprintf("%s has not read %d of their %d piece%s of mail.\n",
capitalize(who), mail_stat["unread"], mail_stat["total"],
(mail_stat["total"] == 1 ? "" : "s"));
else {
msg += "No unread mail" ;
if(this_player()) {
if (adminp(getuid(this_player()))) {
// msg += " ("+mail_stat["total"]+" pieces)" ;
msg += sprintf(" (%d piece%s)", mail_stat["total"], (mail_stat["total"] == 1 ? "" : "s"));
}
}
msg += ".\n" ;
}
tmp1 = (string)link->query("email");
msg += "Email address: " + tmp1 + "\n";
tmp1 = user_path(who) + ".project";
if (file_size(tmp1) >= 0)
msg += "Project: " + read_file(tmp1);
tmp1 = user_path(who) + ".plan";
if (file_size(tmp1) >= 0) {
msg += "Plan:\n" + read_file(tmp1);
} else {
msg += "No Plan.\n";
}
if (!find_player(who) || !interactive(find_player(who))) {
link->remove();
// Some names like .foo weren't getting away.
if(link) destruct(link);
if(link) log_file("fingerdest",sprintf("Connection of %s not dested by finger daemon, on %s.\n", link->query("name"), ctime(time())));
}
return "\n" + msg + "\n";
}
string finger_group(string group) {
int i, j;
string msg;
object link;
mixed tmp1, tmp2, tmp3, tmp4, tmp5;
string *group2;
groups = master()->query_groups();
if (!group || undefinedp(groups[group]))
return "Finger: There is no such group.\n";
/*
* special case: filter root members out of admin group
*/
// if (group == "admin")
// groups["admin"] = filter_array(groups["admin"], "filter_root", this_object());
group2 = groups[group];
j = group2 ? sizeof(group2) : 0;
msg = LINE1;
if (j == 0) {
msg += "[" + capitalize(mud_name()) + "] No members of " +
capitalize(group) + " group (" + ctime(time()) + ").\n";
} else {
msg += "[" + capitalize(mud_name()) + "] " + j +
(j == 1 ? " user" : " users") + " " +
"in " + capitalize(group) + " group (" + ctime(time()) + ").\n";
msg += LINE2;
msg += sprintf("%-12s%-20s%-14s%-28s", "Login", "Real Name",
"Domain", "On\n");
msg += LINE2;
group2 = sort_array(group2, "do_alpha", this_object());
for (i = 0; i < j; i++) {
tmp1 = group2[i]; /* logid id */
link = find_player(tmp1);
if (link)
link = link->query_link();
else
link = restore_data(tmp1);
if (!link)
continue; /* no such user */
tmp2 = (string)link->RNAME; /* real name */
tmp3 = DOMAIN_D->query_domain(link);
if ((tmp3 == 0) || (tmp3 == ""))
tmp3 = "None";
tmp4 = find_player(tmp1);
if (!tmp4 || !filter_users(tmp4))
tmp5 = "Last ";
else
tmp5 = "Since ";
if (!link->query("last_on"))
tmp5 += "(Unavailable)";
else
tmp5 += ctime((int)link->query("last_on"));
msg += sprintf("%-12s%-20s%-14s%28s",
capitalize((string)tmp1),
capitalize(extract((string)tmp2, 0, 18)),
capitalize((string)tmp3),
(string)tmp5 + "\n");
if (!find_player(tmp1))
link->remove();
}
}
return msg + LINE1;
}
string finger_all() {
object *who, link;
int i, j;
string msg;
who = users();
who = filter_array(who, "filter_users", this_object());
who = sort_array(who, "sort_users", this_object());
j = who ? sizeof(who) : 0;
msg = LINE1;
if (j == 0) {
msg += "[" + capitalize(mud_name()) + "] No one is presently " +
"connected (" + ctime(time()) + ").\n";
} else {
msg += "[" + capitalize(mud_name()) + "] " + j +
(j == 1 ? " user" : " users") + " " +
(j == 1 ? "is " : "are ") + "presently connected (" +
ctime(time()) + ").\n";
msg += LINE2;
msg += sprintf("%-12s%-20s%-14s%-7s%-21s", "Login", "Real Name",
"Position", "Idle", "Where\n");
msg += LINE2;
}
for (i = 0; i < j; i++) {
link = (object)who[i]->query_link();
if (!link || !link->RNAME)
continue;
msg += sprintf("%-12s%-20s%-14s%-7s%-21s",
capitalize((string)link->NAME),
capitalize(extract((string)link->RNAME, 0, 18)),
capitalize((string)DOMAIN_D->query_domain_level(link)),
query_idle_string(who[i], 0),
extract(query_ip_name(who[i]), 0, 20) + "\n");
}
return msg + LINE1;
}
// This function filters out any invisible and monster-inhabiting users.
int filter_users(object who) {
if (!this_player() && who->query("invisible"))
return 0;
else if (!visible(who, this_player()))
return 0;
return !((int)who->query("npc"));
}
// This function filters out root members from admin group
int filter_root(string who) {
if (member_array(who, groups["root"]) > -1)
return 0;
return 1;
}
// This function sorts the members in alphabetical order.
int do_alpha(string str1, string str2) {
return strcmp(str1, str2);
}
// This function sorts the users in alphabetical order.
int sort_users(object one, object two) {
return strcmp((string)one->NAME, (string)two->NAME);
}