1 # include <kernel/kernel.h>
2 # include <kernel/user.h>
3 # include <kernel/access.h>
4 
5 inherit LIB_USER;
6 inherit user API_USER;
7 inherit access API_ACCESS;
8 
9 
10 # define STATE_NORMAL		0
11 # define STATE_LOGIN		1
12 # define STATE_OLDPASSWD	2
13 # define STATE_NEWPASSWD1	3
14 # define STATE_NEWPASSWD2	4
15 
16 static string name;		/* user name */
17 static string Name;		/* capitalized user name */
18 static mapping state;		/* state for a connection object */
19 string password;		/* user password */
20 static string newpasswd;	/* new password */
21 static object wiztool;		/* command handler */
22 static int nconn;		/* # of connections */
23 
24 /*
25  * NAME:	create()
26  * DESCRIPTION:	initialize user object
27  */
create(int clone)28 static void create(int clone)
29 {
30     if (clone) {
31 	user::create();
32 	access::create();
33 	state = ([ ]);
34     }
35 }
36 
37 /*
38  * NAME:	tell_audience()
39  * DESCRIPTION:	send message to listening users
40  */
tell_audience(string str)41 private void tell_audience(string str)
42 {
43     object *users, user;
44     int i;
45 
46     users = users();
47     for (i = sizeof(users); --i >= 0; ) {
48 	user = users[i];
49 	if (user != this_object() &&
50 	    sscanf(object_name(user), DEFAULT_USER + "#%*d") != 0) {
51 	    user->message(str);
52 	}
53     }
54 }
55 
56 /*
57  * NAME:	login()
58  * DESCRIPTION:	login a new user
59  */
login(string str)60 int login(string str)
61 {
62     if (previous_program() == LIB_CONN) {
63 	if (nconn == 0) {
64 	    ::login(str);
65 	}
66 	nconn++;
67 	if (strlen(str) == 0 || sscanf(str, "%*s ") != 0 ||
68 	    sscanf(str, "%*s/") != 0) {
69 	    return MODE_DISCONNECT;
70 	}
71 	Name = name = str;
72 	if (Name[0] >= 'a' && Name[0] <= 'z') {
73 	    Name[0] -= 'a' - 'A';
74 	}
75 	restore_object(DEFAULT_USER_DIR + "/" + str + ".pwd");
76 
77 	if (password) {
78 	    /* check password */
79 	    previous_object()->message("Password:");
80 	    state[previous_object()] = STATE_LOGIN;
81 	} else {
82 	    /* no password; login immediately */
83 	    connection(previous_object());
84 	    tell_audience(Name + " logs in.\n");
85 	    if (str != "admin" && sizeof(query_users() & ({ str })) == 0) {
86 		message("> ");
87 		state[previous_object()] = STATE_NORMAL;
88 		return MODE_ECHO;
89 	    }
90 	    if (!wiztool) {
91 		wiztool = clone_object(DEFAULT_WIZTOOL, str);
92 	    }
93 	    message("Pick a new password:");
94 	    state[previous_object()] = STATE_NEWPASSWD1;
95 	}
96 	return MODE_NOECHO;
97     }
98 }
99 
100 /*
101  * NAME:	logout()
102  * DESCRIPTION:	logout user
103  */
logout(int quit)104 void logout(int quit)
105 {
106     if (previous_program() == LIB_CONN && --nconn == 0) {
107 	if (query_conn()) {
108 	    if (quit) {
109 		tell_audience(Name + " logs out.\n");
110 	    } else {
111 		tell_audience(Name + " disconnected.\n");
112 	    }
113 	}
114 	::logout();
115 	if (wiztool) {
116 	    destruct_object(wiztool);
117 	}
118 	destruct_object(this_object());
119     }
120 }
121 
122 /*
123  * NAME:	receive_message()
124  * DESCRIPTION:	process a message from the user
125  */
receive_message(string str)126 int receive_message(string str)
127 {
128     if (previous_program() == LIB_CONN) {
129 	string cmd;
130 	object user, *users;
131 	int i, sz;
132 
133 	switch (state[previous_object()]) {
134 	case STATE_NORMAL:
135 	    cmd = str;
136 	    if (strlen(str) != 0 && str[0] == '!') {
137 		cmd = cmd[1 ..];
138 	    }
139 
140 	    if (!wiztool || !query_editor(wiztool) || cmd != str) {
141 		/* check standard commands */
142 		if (strlen(cmd) != 0) {
143 		    switch (cmd[0]) {
144 		    case '\'':
145 			if (strlen(cmd) > 1) {
146 			    cmd[0] = ' ';
147 			    str = cmd;
148 			}
149 			cmd = "say";
150 			break;
151 
152 		    case ':':
153 			if (strlen(cmd) > 1) {
154 			    cmd[0] = ' ';
155 			    str = cmd;
156 			}
157 			cmd = "emote";
158 			break;
159 
160 		    default:
161 			sscanf(cmd, "%s ", cmd);
162 			break;
163 		    }
164 		}
165 
166 		switch (cmd) {
167 		case "say":
168 		    if (sscanf(str, "%*s %s", str) == 0) {
169 			message("Usage: say <text>\n");
170 		    } else {
171 			tell_audience(Name + " says: " + str + "\n");
172 		    }
173 		    str = nil;
174 		    break;
175 
176 		case "emote":
177 		    if (sscanf(str, "%*s %s", str) == 0) {
178 			message("Usage: emote <text>\n");
179 		    } else {
180 			tell_audience(Name + " " + str + "\n");
181 		    }
182 		    str = nil;
183 		    break;
184 
185 		case "tell":
186 		    if (sscanf(str, "%*s %s %s", cmd, str) != 3 ||
187 			!(user=find_user(cmd))) {
188 			message("Usage: tell <user> <text>\n");
189 		    } else {
190 			user->message(Name + " tells you: " + str + "\n");
191 		    }
192 		    str = nil;
193 		    break;
194 
195 		case "users":
196 		    users = users();
197 		    str = "Logged on:";
198 		    for (i = 0, sz = sizeof(users); i < sz; i++) {
199 			cmd = users[i]->query_name();
200 			if (cmd) {
201 			    str += " " + cmd;
202 			}
203 		    }
204 		    message(str + "\n");
205 		    str = nil;
206 		    break;
207 
208 		case "password":
209 		    if (password) {
210 			message("Old password:");
211 			state[previous_object()] = STATE_OLDPASSWD;
212 		    } else {
213 			message("New password:");
214 			state[previous_object()] = STATE_NEWPASSWD1;
215 		    }
216 		    return MODE_NOECHO;
217 
218 		case "quit":
219 		    return MODE_DISCONNECT;
220 		}
221 	    }
222 
223 	    if (str) {
224 		if (wiztool) {
225 		    wiztool->input(str);
226 		} else if (strlen(str) != 0) {
227 		    message("No command: " + str + "\n");
228 		}
229 	    }
230 	    break;
231 
232 	case STATE_LOGIN:
233 	    if (hash_string("crypt", str, password) != password) {
234 		previous_object()->message("\nBad password.\n");
235 		return MODE_DISCONNECT;
236 	    }
237 	    connection(previous_object());
238 	    message("\n");
239 	    tell_audience(Name + " logs in.\n");
240 	    if (!wiztool &&
241 		(name == "admin" || sizeof(query_users() & ({ name })) != 0)) {
242 		wiztool = clone_object(DEFAULT_WIZTOOL, name);
243 	    }
244 	    break;
245 
246 	case STATE_OLDPASSWD:
247 	    if (hash_string("crypt", str, password) != password) {
248 		message("\nBad password.\n");
249 		break;
250 	    }
251 	    message("\nNew password:");
252 	    state[previous_object()] = STATE_NEWPASSWD1;
253 	    return MODE_NOECHO;
254 
255 	case STATE_NEWPASSWD1:
256 	    newpasswd = str;
257 	    message("\nRetype new password:");
258 	    state[previous_object()] = STATE_NEWPASSWD2;
259 	    return MODE_NOECHO;
260 
261 	case STATE_NEWPASSWD2:
262 	    if (newpasswd == str) {
263 		password = hash_string("crypt", str);
264 		if (wiztool) {
265 		    /* save wizards only */
266 		    save_object(DEFAULT_USER_DIR + "/" + name + ".pwd");
267 		}
268 		message("\nPassword changed.\n");
269 	    } else {
270 		message("\nMismatch; password not changed.\n");
271 	    }
272 	    newpasswd = nil;
273 	    break;
274 	}
275 
276 	str = (wiztool) ? query_editor(wiztool) : nil;
277 	if (str) {
278 	    message((str == "insert") ? "*\b" : ":");
279 	} else {
280 	    message((name == "admin") ? "# " : "> ");
281 	}
282 	state[previous_object()] = STATE_NORMAL;
283 	return MODE_ECHO;
284     }
285 }
286