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