Download
jcs
/subtext
/sysop.c
(View History)
jcs db: Properly close board and folder biles at shutdown | Latest amendment: 297 on 2022-11-30 |
1 | /* |
2 | * Copyright (c) 2022 joshua stein <jcs@jcs.org> |
3 | * |
4 | * Permission to use, copy, modify, and distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above |
6 | * copyright notice and this permission notice appear in all copies. |
7 | * |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ |
16 | |
17 | #include <string.h> |
18 | |
19 | #include "subtext.h" |
20 | #include "ansi.h" |
21 | #include "board.h" |
22 | #include "session.h" |
23 | #include "sysop.h" |
24 | |
25 | #define USERS_PER_PAGE 10 |
26 | |
27 | void sysop_edit_boards(struct session *s); |
28 | void sysop_edit_folders(struct session *s); |
29 | void sysop_edit_motd(struct session *s); |
30 | void sysop_edit_users(struct session *s); |
31 | size_t sysop_find_user_ids(size_t nall_user_ids, |
32 | unsigned long *all_user_ids, unsigned long **user_ids, size_t offset, |
33 | size_t limit); |
34 | void sysop_edit_user(struct session *s, unsigned long id); |
35 | |
36 | void |
37 | sysop_menu(struct session *s) |
38 | { |
39 | static const struct session_menu_option opts[] = { |
40 | { 'm', "Mm", "Edit Message of the Day" }, |
41 | { 'b', "Bb", "Manage Boards" }, |
42 | { 'f', "Ff", "Manage File Folders" }, |
43 | { 'u', "Uu", "Manage Users" }, |
44 | { 's', "Ss", "Change BBS Settings" }, |
45 | { 'q', "QqXx", "Return to main menu" }, |
46 | { '?', "?", "List menu options" }, |
47 | }; |
48 | char c; |
49 | bool show_help = true; |
50 | bool done = false; |
51 | |
52 | if (!s->user || !s->user->is_sysop) |
53 | return; |
54 | |
55 | session_logf(s, "Entered sysop menu"); |
56 | |
57 | while (!done && !s->ending) { |
58 | c = session_menu(s, "Sysop Menu", "Sysop", opts, nitems(opts), |
59 | show_help); |
60 | show_help = false; |
61 | |
62 | switch (c) { |
63 | case 'b': |
64 | sysop_edit_boards(s); |
65 | break; |
66 | case 'f': |
67 | sysop_edit_folders(s); |
68 | break; |
69 | case 'm': |
70 | sysop_edit_motd(s); |
71 | break; |
72 | case 's': |
73 | sysop_edit_settings(s); |
74 | break; |
75 | case 'u': |
76 | sysop_edit_users(s); |
77 | break; |
78 | case '?': |
79 | show_help = true; |
80 | break; |
81 | default: |
82 | done = true; |
83 | break; |
84 | } |
85 | } |
86 | } |
87 | |
88 | void |
89 | sysop_edit_settings(struct session *s) |
90 | { |
91 | struct config *new_config, old_config; |
92 | short ret; |
93 | |
94 | if (!s->user || !s->user->is_sysop) |
95 | return; |
96 | |
97 | ret = struct_editor(s, config_fields, nconfig_fields, &db->config, |
98 | sizeof(struct config), (void *)&new_config, "BBS Settings", |
99 | "Sysop:Settings"); |
100 | if (ret != 0) { |
101 | session_printf(s, "No changes made\r\n"); |
102 | return; |
103 | } |
104 | |
105 | memcpy(&old_config, &db->config, sizeof(db->config)); |
106 | memcpy(&db->config, new_config, sizeof(db->config)); |
107 | db_config_save(db); |
108 | memcpy(&db->config, &old_config, sizeof(db->config)); |
109 | |
110 | session_logf(s, "Changed BBS settings"); |
111 | session_printf(s, "Successfully saved changes to BBS Settings, " |
112 | "restart to take effect\r\n"); |
113 | xfree(&new_config); |
114 | } |
115 | |
116 | void |
117 | sysop_edit_boards(struct session *s) |
118 | { |
119 | static const struct session_menu_option opts[] = { |
120 | { 'n', "Nn", "Create new board" }, |
121 | { 'q', "QqXx", "Return to sysop menu" }, |
122 | { '?', "?", "List menu options" }, |
123 | }; |
124 | char prompt[30]; |
125 | struct session_menu_option *dopts = NULL, *opt; |
126 | struct board *board, *new_board; |
127 | struct bile *new_board_bile; |
128 | size_t n, size; |
129 | short ret; |
130 | char c, *data = NULL; |
131 | bool show_help = true; |
132 | bool done = false; |
133 | bool found = false; |
134 | |
135 | while (!done && !s->ending) { |
136 | /* |
137 | * Unfortunately we have to do this every iteration because the |
138 | * list of boards may change |
139 | */ |
140 | if (dopts != NULL) |
141 | xfree(&dopts); |
142 | dopts = xmalloc(sizeof(opts) + |
143 | (db->nboards * sizeof(struct session_menu_option)), |
144 | "sysop_edit_boards opts"); |
145 | for (n = 0; n < db->nboards; n++) { |
146 | board = &db->boards[n]; |
147 | opt = &dopts[n]; |
148 | opt->ret = '0' + board->id; |
149 | opt->key[0] = '0' + board->id; |
150 | opt->key[1] = '\0'; |
151 | strlcpy(opt->title, board->name, sizeof(opts[0].title)); |
152 | } |
153 | memcpy(&dopts[db->nboards], opts, sizeof(opts)); |
154 | |
155 | c = session_menu(s, "Board Editor", "Sysop:Boards", dopts, |
156 | nitems(opts) + db->nboards, show_help); |
157 | show_help = false; |
158 | |
159 | switch (c) { |
160 | case 'n': |
161 | board = xmalloczero(sizeof(struct board), |
162 | "sysop_edit_boards board"); |
163 | board->id = bile_next_id(db->bile, DB_BOARD_RTYPE); |
164 | board->restricted_posting = false; |
165 | board->restricted_viewing = false; |
166 | ret = struct_editor(s, board_fields, nboard_fields, |
167 | board, sizeof(struct board), (void *)&new_board, |
168 | "New Board", "Sysop:Boards:New"); |
169 | if (ret != 0) { |
170 | xfree(&board); |
171 | continue; |
172 | } |
173 | |
174 | new_board_bile = db_board_create(db, new_board, false); |
175 | bile_close(new_board_bile); |
176 | db_cache_boards(db); |
177 | |
178 | session_logf(s, "Created new board %ld: %s", new_board->id, |
179 | new_board->name); |
180 | xfree(&board); |
181 | xfree(&new_board); |
182 | break; |
183 | case '0': |
184 | case '1': |
185 | case '2': |
186 | case '3': |
187 | case '4': |
188 | case '5': |
189 | case '6': |
190 | case '7': |
191 | case '8': |
192 | case '9': |
193 | found = false; |
194 | for (n = 0; n < db->nboards; n++) { |
195 | board = &db->boards[n]; |
196 | if (board->id != c - '0') |
197 | continue; |
198 | found = true; |
199 | snprintf(prompt, sizeof(prompt), "Sysop:Boards:%ld", |
200 | board->id); |
201 | ret = struct_editor(s, board_fields, nboard_fields, |
202 | board, sizeof(struct board), (void *)&new_board, |
203 | "Edit Board", prompt); |
204 | if (ret != 0) |
205 | continue; |
206 | memcpy(&db->boards[n], new_board, sizeof(struct board)); |
207 | |
208 | ret = bile_marshall_object(db->bile, board_object_fields, |
209 | nboard_object_fields, &db->boards[n], &data, &size, |
210 | "sysop_edit_boards"); |
211 | if (ret != 0 || size == 0) |
212 | panic("db_board_create: failed to marshall object"); |
213 | |
214 | if (bile_write(db->bile, DB_BOARD_RTYPE, new_board->id, |
215 | data, size) != size) |
216 | panic("save of board failed: %d", bile_error(db->bile)); |
217 | xfree(&data); |
218 | |
219 | session_logf(s, "Saved changes to board %ld: %s", |
220 | new_board->id, new_board->name); |
221 | xfree(&new_board); |
222 | break; |
223 | } |
224 | if (!found) { |
225 | session_printf(s, "Invalid board ID\r\n"); |
226 | session_flush(s); |
227 | } |
228 | break; |
229 | case '?': |
230 | show_help = true; |
231 | break; |
232 | default: |
233 | done = true; |
234 | break; |
235 | } |
236 | } |
237 | } |
238 | |
239 | void |
240 | sysop_edit_folders(struct session *s) |
241 | { |
242 | static const struct session_menu_option opts[] = { |
243 | { 'n', "Nn", "Create new folder" }, |
244 | { 'q', "QqXx", "Return to sysop menu" }, |
245 | { '?', "?", "List menu options" }, |
246 | }; |
247 | char prompt[30]; |
248 | struct session_menu_option *dopts = NULL, *opt; |
249 | struct folder *folder, *new_folder; |
250 | struct bile *new_folder_bile; |
251 | size_t n, size; |
252 | short ret; |
253 | char c, *data = NULL; |
254 | bool show_help = true; |
255 | bool done = false; |
256 | bool found = false; |
257 | |
258 | while (!done && !s->ending) { |
259 | /* |
260 | * Unfortunately we have to do this every iteration because the |
261 | * list of boards may change |
262 | */ |
263 | if (dopts != NULL) |
264 | xfree(&dopts); |
265 | dopts = xmalloc(sizeof(opts) + |
266 | (db->nboards * sizeof(struct session_menu_option)), |
267 | "sysop_edit_folders opts"); |
268 | for (n = 0; n < db->nfolders; n++) { |
269 | folder = &db->folders[n]; |
270 | opt = &dopts[n]; |
271 | opt->ret = '0' + folder->id; |
272 | opt->key[0] = '0' + folder->id; |
273 | opt->key[1] = '\0'; |
274 | strlcpy(opt->title, folder->name, sizeof(opts[0].title)); |
275 | } |
276 | memcpy(&dopts[db->nfolders], opts, sizeof(opts)); |
277 | |
278 | c = session_menu(s, "Folder Editor", "Sysop:Folders", dopts, |
279 | nitems(opts) + db->nfolders, show_help); |
280 | show_help = false; |
281 | |
282 | switch (c) { |
283 | case 'n': |
284 | folder = xmalloczero(sizeof(struct folder), |
285 | "sysop_edit_folders folder"); |
286 | folder->id = bile_next_id(db->bile, DB_FOLDER_RTYPE); |
287 | folder->restricted_posting = false; |
288 | folder->restricted_viewing = false; |
289 | ret = struct_editor(s, folder_fields, nfolder_fields, |
290 | folder, sizeof(struct folder), (void *)&new_folder, |
291 | "New Folder", "Sysop:Folders:New"); |
292 | if (ret != 0) { |
293 | xfree(&folder); |
294 | continue; |
295 | } |
296 | |
297 | new_folder_bile = db_folder_create(db, new_folder, false); |
298 | bile_close(new_folder_bile); |
299 | db_cache_folders(db); |
300 | |
301 | session_logf(s, "Created new folder %ld: %s", new_folder->id, |
302 | new_folder->name); |
303 | xfree(&folder); |
304 | xfree(&new_folder); |
305 | break; |
306 | case '0': |
307 | case '1': |
308 | case '2': |
309 | case '3': |
310 | case '4': |
311 | case '5': |
312 | case '6': |
313 | case '7': |
314 | case '8': |
315 | case '9': |
316 | found = false; |
317 | for (n = 0; n < db->nfolders; n++) { |
318 | folder = &db->folders[n]; |
319 | if (folder->id != c - '0') |
320 | continue; |
321 | found = true; |
322 | snprintf(prompt, sizeof(prompt), "Sysop:Folders:%ld", |
323 | folder->id); |
324 | ret = struct_editor(s, folder_fields, nfolder_fields, |
325 | folder, sizeof(struct folder), (void *)&new_folder, |
326 | "Edit Folder", prompt); |
327 | if (ret != 0) |
328 | continue; |
329 | memcpy(&db->folders[n], new_folder, sizeof(struct folder)); |
330 | |
331 | ret = bile_marshall_object(db->bile, folder_object_fields, |
332 | nfolder_object_fields, &db->folders[n], &data, &size, |
333 | "sysop_edit_folders"); |
334 | if (ret != 0 || size == 0) |
335 | panic("db_folder_create: failed to marshall object"); |
336 | |
337 | if (bile_write(db->bile, DB_FOLDER_RTYPE, new_folder->id, |
338 | data, size) != size) |
339 | panic("save of folder failed: %d", |
340 | bile_error(db->bile)); |
341 | xfree(&data); |
342 | |
343 | session_logf(s, "Saved changes to folder %ld: %s", |
344 | new_folder->id, new_folder->name); |
345 | xfree(&new_folder); |
346 | break; |
347 | } |
348 | if (!found) { |
349 | session_printf(s, "Invalid folder ID\r\n"); |
350 | session_flush(s); |
351 | } |
352 | break; |
353 | case '?': |
354 | show_help = true; |
355 | break; |
356 | default: |
357 | done = true; |
358 | break; |
359 | } |
360 | } |
361 | } |
362 | |
363 | void |
364 | sysop_edit_motd(struct session *s) |
365 | { |
366 | static const struct session_menu_option opts[] = { |
367 | { 'n', "Nn", "Create new MOTD" }, |
368 | { 's', "Ss", "Show latest MOTD" }, |
369 | { 'q', "QqXx", "Return to sysop menu" }, |
370 | { '?', "?", "List menu options" }, |
371 | }; |
372 | char prompt[30]; |
373 | struct session_menu_option *opt; |
374 | size_t n, size; |
375 | short ret; |
376 | char c, *data = NULL; |
377 | bool show_help = true; |
378 | bool done = false; |
379 | bool found = false; |
380 | |
381 | while (!done && !s->ending) { |
382 | c = session_menu(s, "MOTD Editor", "Sysop:MOTD", opts, |
383 | nitems(opts), show_help); |
384 | show_help = false; |
385 | |
386 | switch (c) { |
387 | case 's': { |
388 | session_print_motd(s, true); |
389 | break; |
390 | } |
391 | case 'n': { |
392 | char *motd = NULL, *tmp = NULL, c; |
393 | struct bile_object *old_motd; |
394 | unsigned long new_id; |
395 | |
396 | motd_write: |
397 | session_printf(s, "MOTD Text:\r\n"); |
398 | session_flush(s); |
399 | |
400 | tmp = session_field_input(s, 2048, s->terminal_columns - 1, |
401 | motd, true, 0); |
402 | session_output(s, "\r\n", 2); |
403 | session_flush(s); |
404 | |
405 | rtrim(tmp, "\r\n\t "); |
406 | |
407 | if (motd) |
408 | xfree(&motd); |
409 | motd = tmp; |
410 | |
411 | session_printf(s, "\r\n{{B}}(S){{/B}}ave MOTD, " |
412 | "{{B}}(E){{/B}}dit again, or {{B}}(C){{/B}}ancel? "); |
413 | session_flush(s); |
414 | |
415 | c = session_input_char(s); |
416 | if (c == 0 && s->obuflen > 0) { |
417 | s->node_funcs->output(s); |
418 | uthread_yield(); |
419 | xfree(&motd); |
420 | break; |
421 | } |
422 | |
423 | session_printf(s, "%c\r\n", c); |
424 | session_flush(s); |
425 | |
426 | switch (c) { |
427 | case 's': |
428 | case 'S': |
429 | case 'y': |
430 | case '\n': |
431 | case '\r': |
432 | /* save */ |
433 | session_printf(s, "Saving MOTD..."); |
434 | session_flush(s); |
435 | |
436 | new_id = bile_next_id(db->bile, DB_MOTD_RTYPE); |
437 | old_motd = bile_get_nth_of_type(db->bile, 0, |
438 | DB_MOTD_RTYPE); |
439 | if (old_motd) { |
440 | bile_delete(db->bile, DB_MOTD_RTYPE, old_motd->id); |
441 | xfree(&old_motd); |
442 | } |
443 | bile_write(db->bile, DB_MOTD_RTYPE, new_id, motd, |
444 | strlen(motd) + 1); |
445 | |
446 | session_printf(s, " saved!\r\n"); |
447 | session_flush(s); |
448 | break; |
449 | case 'e': |
450 | case 'E': |
451 | goto motd_write; |
452 | break; |
453 | case 'c': |
454 | case 'C': |
455 | case CONTROL_C: |
456 | xfree(&motd); |
457 | break; |
458 | } |
459 | break; |
460 | } |
461 | case '?': |
462 | show_help = true; |
463 | break; |
464 | default: |
465 | done = true; |
466 | break; |
467 | } |
468 | } |
469 | } |
470 | |
471 | void |
472 | sysop_edit_users(struct session *s) |
473 | { |
474 | static const struct session_menu_option opts[] = { |
475 | { '#', "#0123456789", "Edit user [#]" }, |
476 | { '<', "<", "Previous page of users" }, |
477 | { 'l', "Ll", "List users" }, |
478 | { '>', ">", "Next page of users" }, |
479 | { 'q', "QqXx", "Return to sysop menu" }, |
480 | { '?', "?", "List menu options" }, |
481 | }; |
482 | unsigned long *all_user_ids = NULL, *user_ids = NULL; |
483 | struct user user; |
484 | size_t pages, page, n, size, nall_user_ids, nuser_ids; |
485 | char c; |
486 | char time[30]; |
487 | bool show_help = false; |
488 | bool show_list = true; |
489 | bool done = false; |
490 | bool find_user_ids = true; |
491 | |
492 | nall_user_ids = bile_sorted_ids_by_type(db->bile, DB_USER_RTYPE, |
493 | &all_user_ids); |
494 | page = 0; |
495 | |
496 | while (!done && !s->ending) { |
497 | if (find_user_ids) { |
498 | nuser_ids = sysop_find_user_ids(nall_user_ids, all_user_ids, |
499 | &user_ids, page * USERS_PER_PAGE, USERS_PER_PAGE); |
500 | /* ceil(nall_user_ids / USERS_PER_PAGE) */ |
501 | pages = (nall_user_ids + USERS_PER_PAGE - 1) / USERS_PER_PAGE; |
502 | |
503 | if (page >= pages) |
504 | page = pages - 1; |
505 | |
506 | find_user_ids = false; |
507 | } |
508 | |
509 | if (show_list) { |
510 | session_printf(s, "{{B}}Users (Page %ld of %ld){{/B}}\r\n", |
511 | page + 1, pages); |
512 | session_printf(s, "%s# Username ID Active Sysop Last Login%s\r\n", |
513 | ansi(s, ANSI_BOLD, ANSI_END), ansi(s, ANSI_RESET, ANSI_END)); |
514 | session_flush(s); |
515 | |
516 | for (n = 0; n < nuser_ids; n++) { |
517 | size = bile_read(db->bile, DB_USER_RTYPE, user_ids[n], |
518 | (char *)&user, sizeof(struct user)); |
519 | if (size == 0) |
520 | continue; |
521 | if (user.last_seen_at) |
522 | strftime(time, sizeof(time), "%Y-%m-%d %H:%M", |
523 | localtime(&user.last_seen_at)); |
524 | else |
525 | snprintf(time, sizeof(time), "Never"); |
526 | session_printf(s, "%ld %-14s %-5ld %c %c %s\r\n", |
527 | n, |
528 | user.username, |
529 | user.id, |
530 | user.is_enabled ? 'Y' : ' ', |
531 | user.is_sysop ? 'Y' : ' ', |
532 | time); |
533 | session_flush(s); |
534 | } |
535 | show_list = false; |
536 | } |
537 | |
538 | c = session_menu(s, "Edit Users", "Sysop:Users", opts, |
539 | nitems(opts), show_help); |
540 | show_help = false; |
541 | |
542 | handle_opt: |
543 | switch (c) { |
544 | case 'l': |
545 | show_list = true; |
546 | break; |
547 | case '>': |
548 | case '<': |
549 | if (c == '>' && page == pages - 1) { |
550 | session_printf(s, "You are at the last page of posts\r\n"); |
551 | session_flush(s); |
552 | break; |
553 | } |
554 | if (c == '<' && page == 0) { |
555 | session_printf(s, "You are already at the first page\r\n"); |
556 | session_flush(s); |
557 | break; |
558 | } |
559 | if (c == '>') |
560 | page++; |
561 | else |
562 | page--; |
563 | find_user_ids = true; |
564 | show_list = true; |
565 | break; |
566 | case 0: |
567 | case 1: |
568 | case 2: |
569 | case 3: |
570 | case 4: |
571 | case 5: |
572 | case 6: |
573 | case 7: |
574 | case 8: |
575 | case 9: |
576 | if (c >= nuser_ids) { |
577 | session_printf(s, "Invalid user\r\n"); |
578 | session_flush(s); |
579 | break; |
580 | } |
581 | sysop_edit_user(s, user_ids[c]); |
582 | break; |
583 | case '?': |
584 | show_help = true; |
585 | break; |
586 | default: |
587 | done = true; |
588 | break; |
589 | } |
590 | } |
591 | |
592 | if (all_user_ids != NULL) |
593 | xfree(&all_user_ids); |
594 | } |
595 | |
596 | size_t |
597 | sysop_find_user_ids(size_t nall_user_ids, unsigned long *all_user_ids, |
598 | unsigned long **user_ids, size_t offset, size_t limit) |
599 | { |
600 | size_t nuser_ids, n; |
601 | |
602 | if (nall_user_ids < offset) |
603 | return 0; |
604 | |
605 | nuser_ids = nall_user_ids - offset; |
606 | if (nuser_ids > limit) |
607 | nuser_ids = limit; |
608 | |
609 | *user_ids = xcalloc(sizeof(unsigned long), nuser_ids, |
610 | "sysop_find_user_ids"); |
611 | |
612 | for (n = 0; n < nuser_ids; n++) { |
613 | (*user_ids)[n] = all_user_ids[offset + n]; |
614 | } |
615 | |
616 | return nuser_ids; |
617 | } |
618 | |
619 | void |
620 | sysop_edit_user(struct session *s, unsigned long id) |
621 | { |
622 | static const struct session_menu_option opts[] = { |
623 | { 'd', "Dd", "Delete account" }, |
624 | { 'e', "Ee", "Enable/disable account" }, |
625 | { 'p', "Pp", "Change password" }, |
626 | { 's', "Ss", "Toggle sysop flag" }, |
627 | { 'q', "QqXx", "Return to users menu" }, |
628 | { '?', "?", "List menu options" }, |
629 | }; |
630 | char title[50]; |
631 | char prompt[25]; |
632 | struct user user; |
633 | size_t size; |
634 | bool done = false; |
635 | bool show_help = true; |
636 | char c; |
637 | short cc; |
638 | |
639 | size = bile_read(db->bile, DB_USER_RTYPE, id, (char *)&user, |
640 | sizeof(struct user)); |
641 | if (!size) { |
642 | session_printf(s, "Error: Failed to find user %ld\r\n", id); |
643 | session_flush(s); |
644 | return; |
645 | } |
646 | |
647 | snprintf(title, sizeof(title), "Edit User %s", user.username); |
648 | snprintf(prompt, sizeof(prompt), "Sysop:Users:%ld", user.id); |
649 | |
650 | while (!done && !s->ending) { |
651 | c = session_menu(s, title, prompt, opts, nitems(opts), |
652 | show_help); |
653 | show_help = false; |
654 | |
655 | handle_opt: |
656 | switch (c) { |
657 | case 'd': |
658 | session_printf(s, "Are you sure you want to permanently " |
659 | "delete {{B}}%s{{/B}}? [y/N] ", user.username); |
660 | session_flush(s); |
661 | |
662 | cc = session_input_char(s); |
663 | if (cc == 'y' || c == 'Y') { |
664 | session_printf(s, "%c\r\n", cc); |
665 | session_flush(s); |
666 | user_delete(&user); |
667 | session_printf(s, "\r\n{{B}}User deleted!{{/B}}\r\n"); |
668 | done = true; |
669 | } else { |
670 | session_printf(s, "\r\nUser not deleted.\r\n"); |
671 | session_flush(s); |
672 | } |
673 | break; |
674 | case 'e': |
675 | user.is_enabled = !user.is_enabled; |
676 | user_save(&user); |
677 | break; |
678 | case 'p': |
679 | user_change_password(s, &user); |
680 | break; |
681 | case 's': |
682 | if (strcmp(s->user->username, user.username) == 0) { |
683 | session_printf(s, "You cannot remove your own sysop " |
684 | "flag.\r\n"); |
685 | session_flush(s); |
686 | break; |
687 | } |
688 | user.is_sysop = !user.is_sysop; |
689 | user_save(&user); |
690 | break; |
691 | case '?': |
692 | show_help = true; |
693 | break; |
694 | default: |
695 | done = true; |
696 | break; |
697 | } |
698 | } |
699 | } |