]> code.citadel.org Git - citadel.git/blob - citadel/user_ops.c
remove duplicated declarations
[citadel.git] / citadel / user_ops.c
1 /* needed to properly enable crypt() stuff on some systems */
2 #define _XOPEN_SOURCE
3 /* needed for str[n]casecmp() on some systems if the above is defined */
4 #define _XOPEN_SOURCE_EXTENDED
5
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <stdio.h>
9 #include <fcntl.h>
10 #include <signal.h>
11 #include <pwd.h>
12 #include <sys/types.h>
13 #include <sys/time.h>
14 #include <string.h>
15 #include <syslog.h>
16 #include <pthread.h>
17 #include "citadel.h"
18 #include "server.h"
19 #include "database.h"
20 #include "user_ops.h"
21 #include "sysdep_decls.h"
22 #include "support.h"
23 #include "hooks.h"
24 #include "room_ops.h"
25 #include "logging.h"
26 #include "file_ops.h"
27 #include "control.h"
28 #include "msgbase.h"
29 #include "config.h"
30
31
32 /*
33  * hash()  -  hash table function for user lookup
34  */
35 int hash(char *str)
36 {
37         int h = 0;
38         int i;
39
40         for (i=0; i<strlen(str); ++i) h=h+((i+1)*tolower(str[i]));
41         return(h);
42         }
43
44
45 /*
46  * getuser()  -  retrieve named user into supplied buffer.
47  *               returns 0 on success
48  */
49 int getuser(struct usersupp *usbuf, char name[]) {
50
51         char lowercase_name[32];
52         int a;
53         struct cdbdata *cdbus;
54
55         bzero(usbuf, sizeof(struct usersupp));
56         for (a=0; a<=strlen(name); ++a) {
57                 lowercase_name[a] = tolower(name[a]);
58                 }
59
60         cdbus = cdb_fetch(CDB_USERSUPP, lowercase_name, strlen(lowercase_name));
61         if (cdbus == NULL) {
62                 return(1);      /* user not found */
63                 }
64
65         memcpy(usbuf, cdbus->ptr,
66                 ( (cdbus->len > sizeof(struct usersupp)) ?
67                 sizeof(struct usersupp) : cdbus->len) );
68         cdb_free(cdbus);
69         return(0);
70         }
71
72
73 /*
74  * lgetuser()  -  same as getuser() but locks the record
75  */
76 int lgetuser(struct usersupp *usbuf, char *name)
77 {
78         int retcode;
79
80         retcode = getuser(usbuf,name);
81         if (retcode == 0) {
82                 begin_critical_section(S_USERSUPP);
83                 }
84         return(retcode);
85         }
86
87
88 /*
89  * putuser()  -  write user buffer into the correct place on disk
90  */
91 void putuser(struct usersupp *usbuf, char *name)
92 {
93         char lowercase_name[32];
94         int a;
95
96         for (a=0; a<=strlen(name); ++a) {
97                 lowercase_name[a] = tolower(name[a]);
98                 }
99
100         cdb_store(CDB_USERSUPP,
101                 lowercase_name, strlen(lowercase_name),
102                 usbuf, sizeof(struct usersupp));
103
104         }
105
106
107 /*
108  * lputuser()  -  same as putuser() but locks the record
109  */
110 void lputuser(struct usersupp *usbuf, char *name) {
111         putuser(usbuf,name);
112         end_critical_section(S_USERSUPP);
113         }
114
115
116 /*
117  * Is the user currently logged in an Aide?
118  */
119 int is_aide(void) {
120         if (CC->usersupp.axlevel >= 6) return(1);
121         else return(0);
122         }
123
124
125 /*
126  * Is the user currently logged in an Aide *or* the room aide for this room?
127  */
128 int is_room_aide(void) {
129         if ( (CC->usersupp.axlevel >= 6)
130            || (CC->quickroom.QRroomaide == CC->usersupp.usernum) ) {
131                 return(1);
132                 }
133         else {
134                 return(0);
135                 }
136         }
137
138 /*
139  * getuserbynumber()  -  get user by number
140  *                       returns 0 if user was found
141  */
142 int getuserbynumber(struct usersupp *usbuf, long int number)
143 {
144         struct cdbdata *cdbus;
145
146         cdb_rewind(CDB_USERSUPP);
147
148         while(cdbus = cdb_next_item(CDB_USERSUPP), cdbus != NULL) {
149                 bzero(usbuf, sizeof(struct usersupp));
150                 memcpy(usbuf, cdbus->ptr,
151                         ( (cdbus->len > sizeof(struct usersupp)) ?
152                         sizeof(struct usersupp) : cdbus->len) );
153                 cdb_free(cdbus);
154                 if (usbuf->usernum == number) {
155                         return(0);
156                         }
157                 }
158         return(-1);
159         }
160
161
162 /*
163  * USER cmd
164  */
165 void cmd_user(char *cmdbuf)
166 {
167         char username[256];
168         char autoname[256];
169         int found_user = 0;
170         struct passwd *p;
171         int a;
172
173         extract(username,cmdbuf,0);
174         username[25] = 0;
175         strproc(username);
176
177         if ((CC->logged_in)) {
178                 cprintf("%d Already logged in.\n",ERROR);
179                 return;
180                 }
181
182         found_user = getuser(&CC->usersupp,username);
183         if (found_user != 0) {
184                 p = (struct passwd *)getpwnam(username);
185                 if (p!=NULL) {
186                         strcpy(autoname,p->pw_gecos);
187                         for (a=0; a<strlen(autoname); ++a)
188                                 if (autoname[a]==',') autoname[a]=0;
189                         found_user = getuser(&CC->usersupp,autoname);
190                         }
191                 }
192         if (found_user == 0) {
193                 if (((CC->nologin)) && (CC->usersupp.axlevel < 6)) {
194                         cprintf("%d %s: Too many users are already online (maximum is %d)\n",
195                         ERROR+MAX_SESSIONS_EXCEEDED,
196                         config.c_nodename,config.c_maxsessions);
197                         }
198                 else {
199                         strcpy(CC->curr_user,CC->usersupp.fullname);
200                         cprintf("%d Password required for %s\n",
201                                 MORE_DATA,CC->curr_user);
202                         }
203                 }
204         else {
205                 cprintf("%d %s not found.\n",ERROR,username);
206                 }
207         }
208
209
210
211 /*
212  * session startup code which is common to both cmd_pass() and cmd_newu()
213  */
214 void session_startup(void) {
215         int a;
216         struct quickroom qr;
217
218         syslog(LOG_NOTICE,"user <%s> logged in",CC->curr_user);
219         hook_user_login(CC->cs_pid, CC->curr_user);
220         lgetuser(&CC->usersupp,CC->curr_user);
221         ++(CC->usersupp.timescalled);
222         CC->fake_username[0] = '\0';
223         CC->fake_postname[0] = '\0';
224         CC->fake_hostname[0] = '\0';
225         CC->fake_roomname[0] = '\0';
226         CC->last_pager[0] = '\0';
227         time(&CC->usersupp.lastcall);
228
229         /* If this user's name is the name of the system administrator
230          * (as specified in setup), automatically assign access level 6.
231          */
232         if (!strcasecmp(CC->usersupp.fullname, config.c_sysadm)) {
233                 CC->usersupp.axlevel = 6;
234                 }
235
236 /* A room's generation number changes each time it is recycled. Users are kept
237  * out of private rooms or forget rooms by matching the generation numbers. To
238  * avoid an accidental matchup, unmatched numbers are set to -1 here.
239  */
240         for (a=0; a<MAXROOMS; ++a) {
241                 getroom(&qr,a);
242                 if (CC->usersupp.generation[a] != qr.QRgen)
243                                         CC->usersupp.generation[a]=(-1);
244                 if (CC->usersupp.forget[a] != qr.QRgen)
245                                         CC->usersupp.forget[a]=(-1);
246                 }
247
248         lputuser(&CC->usersupp,CC->curr_user);
249
250         cprintf("%d %s|%d|%d|%d|%u|%ld\n",OK,CC->usersupp.fullname,CC->usersupp.axlevel,
251                 CC->usersupp.timescalled,CC->usersupp.posted,CC->usersupp.flags,
252                 CC->usersupp.usernum);
253         usergoto(0,0);          /* Enter the lobby */   
254         rec_log(CL_LOGIN,CC->curr_user);
255         }
256
257
258
259 /* 
260  * misc things to be taken care of when a user is logged out
261  */
262 void logout(struct CitContext *who)
263 {
264         who->logged_in = 0;
265         if (who->download_fp != NULL) {
266                 fclose(who->download_fp);
267                 who->download_fp = NULL;
268                 }
269         if (who->upload_fp != NULL) {
270                 abort_upl(who);
271                 }
272         }
273
274
275 void cmd_pass(char *buf)
276 {
277         char password[256];
278         int code;
279         struct passwd *p;
280
281         extract(password,buf,0);
282
283         if ((CC->logged_in)) {
284                 cprintf("%d Already logged in.\n",ERROR);
285                 return;
286                 }
287         if (!strcmp(CC->curr_user,"")) {
288                 cprintf("%d You must send a name with USER first.\n",ERROR);
289                 return;
290                 }
291         if (getuser(&CC->usersupp,CC->curr_user)) {
292                 cprintf("%d Can't find user record!\n",ERROR+INTERNAL_ERROR);
293                 return;
294                 }
295
296         code = (-1);
297         if (CC->usersupp.USuid == BBSUID) {
298                 strproc(password);
299                 strproc(CC->usersupp.password);
300                 code = strcasecmp(CC->usersupp.password,password);
301                 }
302         else {
303                 p = (struct passwd *)getpwuid(CC->usersupp.USuid);
304 #ifdef ENABLE_AUTOLOGIN
305                 if (p!=NULL) {
306                         if (!strcmp(p->pw_passwd,
307                            (char *)crypt(password,p->pw_passwd))) {
308                                 code = 0;
309                                 lgetuser(&CC->usersupp, CC->curr_user);
310                                 strcpy(CC->usersupp.password, password);
311                                 lputuser(&CC->usersupp, CC->curr_user);
312                                 }
313                         }
314 #endif
315                 }
316
317         if (!code) {
318                 (CC->logged_in) = 1;
319                 session_startup();
320                 }
321         else {
322                 cprintf("%d Wrong password.\n",ERROR);
323                 rec_log(CL_BADPW,CC->curr_user);
324                 }
325         }
326
327
328 /*
329  * Delete a user record *and* all of its related resources.
330  */
331 int purge_user(char *pname) {
332         char filename[64];
333         struct usersupp usbuf;
334         int a;
335         struct cdbdata *cdbmb;
336         long *mailbox;
337         int num_mails;
338
339         if (getuser(&usbuf, pname) != 0) {
340                 lprintf(5, "Cannot purge user <%s> - not found\n", pname);
341                 return(1);
342                 }
343
344         /* FIX   Don't delete a user who is currently logged in. */
345
346         /* delete any messages in the user's mailbox */
347         cdbmb = cdb_fetch(CDB_MAILBOXES, &usbuf.usernum, sizeof(long));
348         if (cdbmb != NULL) {
349                 num_mails = cdbmb->len / sizeof(long);
350                 mailbox = (long *) cdbmb->ptr;
351                 if (num_mails > 0) for (a=0; a<num_mails; ++a) {
352                         cdb_delete(CDB_MSGMAIN, &mailbox[a], sizeof(long));
353                         }
354                 cdb_free(cdbmb);
355                 /* now delete the mailbox itself */
356                 cdb_delete(CDB_MAILBOXES, &usbuf.usernum, sizeof(long));
357                 }
358
359
360         /* delete the userlog entry */
361         cdb_delete(CDB_USERSUPP, pname, strlen(pname));
362
363         /* remove the user's bio file */        
364         sprintf(filename, "./bio/%ld", usbuf.usernum);
365         unlink(filename);
366
367         /* remove the user's picture */
368         sprintf(filename, "./userpics/%ld.gif", usbuf.usernum);
369         unlink(filename);
370
371         return(0);
372         }
373
374
375 /*
376  * create_user()  -  back end processing to create a new user
377  */
378 int create_user(char *newusername)
379 {
380         struct usersupp usbuf;
381         int a;
382         struct passwd *p = NULL;
383         char username[64];
384
385         strcpy(username, newusername);
386         strproc(username);
387
388 #ifdef ENABLE_AUTOLOGIN
389         p = (struct passwd *)getpwnam(username);
390 #endif
391         if (p != NULL) {
392                 strcpy(username, p->pw_gecos);
393                 for (a=0; a<strlen(username); ++a) {
394                         if (username[a] == ',') username[a] = 0;
395                         }
396                 CC->usersupp.USuid = p->pw_uid;
397                 }
398         else {
399                 CC->usersupp.USuid = BBSUID;
400                 }
401
402         if (!getuser(&usbuf,username)) {
403                 return(ERROR+ALREADY_EXISTS);
404                 }
405
406         strcpy(CC->curr_user,username);
407         strcpy(CC->usersupp.fullname,username);
408         (CC->logged_in) = 1;
409
410         for (a=0; a<MAXROOMS; ++a) {
411                 CC->usersupp.lastseen[a]=0L;
412                 CC->usersupp.generation[a]=(-1);
413                 CC->usersupp.forget[a]=(-1);
414                 }
415         strcpy(CC->usersupp.password,"");
416
417         /* These are the default flags on new accounts */
418         CC->usersupp.flags =
419                 US_NEEDVALID|US_LASTOLD|US_DISAPPEAR|US_PAGINATOR|US_FLOORS;
420
421         CC->usersupp.timescalled = 0;
422         CC->usersupp.posted = 0;
423         CC->usersupp.axlevel = INITAX;
424         CC->usersupp.USscreenwidth = 80;
425         CC->usersupp.USscreenheight = 24;
426         time(&CC->usersupp.lastcall);
427         strcpy(CC->usersupp.USname, "");
428         strcpy(CC->usersupp.USaddr, "");
429         strcpy(CC->usersupp.UScity, "");
430         strcpy(CC->usersupp.USstate, "");
431         strcpy(CC->usersupp.USzip, "");
432         strcpy(CC->usersupp.USphone, "");
433
434         /* fetch a new user number */
435         CC->usersupp.usernum = get_new_user_number();
436
437         if (CC->usersupp.usernum == 1L) {
438                 CC->usersupp.axlevel = 6;
439                 }
440
441         /* add user to userlog */
442         putuser(&CC->usersupp,CC->curr_user);
443         if (getuser(&CC->usersupp,CC->curr_user)) {
444                 return(ERROR+INTERNAL_ERROR);
445                 }
446         rec_log(CL_NEWUSER,CC->curr_user);
447         return(0);
448         }
449
450
451
452
453 /*
454  * cmd_newu()  -  create a new user account
455  */
456 void cmd_newu(char *cmdbuf)
457 {
458         int a;
459         char username[256];
460
461         if ((CC->logged_in)) {
462                 cprintf("%d Already logged in.\n",ERROR);
463                 return;
464                 }
465
466         if ((CC->nologin)) {
467                 cprintf("%d %s: Too many users are already online (maximum is %d)\n",
468                 ERROR+MAX_SESSIONS_EXCEEDED,
469                 config.c_nodename,config.c_maxsessions);
470                 }
471
472         extract(username,cmdbuf,0);
473         username[25] = 0;
474         strproc(username);
475
476         if (strlen(username)==0) {
477                 cprintf("%d You must supply a user name.\n",ERROR);
478                 return;
479                 }
480
481         a = create_user(username);
482         if ((!strcasecmp(username, "bbs")) ||
483             (!strcasecmp(username, "new")) ||
484             (!strcasecmp(username, ".")))
485         {
486            cprintf("%d '%s' is an invalid login name.\n", ERROR);
487            return;
488         }
489         if (a==ERROR+ALREADY_EXISTS) {
490                 cprintf("%d '%s' already exists.\n",
491                         ERROR+ALREADY_EXISTS,username);
492                 return;
493                 }
494         else if (a==ERROR+INTERNAL_ERROR) {
495                 cprintf("%d Internal error - user record disappeared?\n",
496                         ERROR+INTERNAL_ERROR);
497                 return;
498                 }
499         else if (a==0) {
500                 session_startup();
501                 }
502         else {
503                 cprintf("%d unknown error\n",ERROR);
504                 }
505         rec_log(CL_NEWUSER,CC->curr_user);
506         }
507
508
509
510 /*
511  * set password
512  */
513 void cmd_setp(char *new_pw)
514 {
515         if (!(CC->logged_in)) {
516                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
517                 return;
518                 }
519         if (CC->usersupp.USuid != BBSUID) {
520                 cprintf("%d Not allowed.  Use the 'passwd' command.\n",ERROR);
521                 return;
522                 }
523         strproc(new_pw);
524         if (strlen(new_pw)==0) {
525                 cprintf("%d Password unchanged.\n",OK);
526                 return;
527                 }
528         lgetuser(&CC->usersupp,CC->curr_user);
529         strcpy(CC->usersupp.password,new_pw);
530         lputuser(&CC->usersupp,CC->curr_user);
531         cprintf("%d Password changed.\n",OK);
532         rec_log(CL_PWCHANGE,CC->curr_user);
533         }
534
535 /*
536  * get user parameters
537  */
538 void cmd_getu(void) {
539         if (!(CC->logged_in)) {
540                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
541                 return;
542                 }
543         getuser(&CC->usersupp,CC->curr_user);
544         cprintf("%d %d|%d|%d\n",
545                 OK,
546                 CC->usersupp.USscreenwidth,
547                 CC->usersupp.USscreenheight,
548                 (CC->usersupp.flags & US_USER_SET)
549                 );
550         }
551
552 /*
553  * set user parameters
554  */
555 void cmd_setu(char *new_parms)
556 {
557
558         if (num_parms(new_parms)!=3) {
559                 cprintf("%d Usage error.\n",ERROR);
560                 return;
561                 }       
562         if (!(CC->logged_in)) {
563                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
564                 return;
565                 }
566         lgetuser(&CC->usersupp,CC->curr_user);
567         CC->usersupp.USscreenwidth = extract_int(new_parms,0);
568         CC->usersupp.USscreenheight = extract_int(new_parms,1);
569         CC->usersupp.flags = CC->usersupp.flags & (~US_USER_SET);
570         CC->usersupp.flags = CC->usersupp.flags | 
571                 (extract_int(new_parms,2) & US_USER_SET);
572         lputuser(&CC->usersupp,CC->curr_user);
573         cprintf("%d Ok\n",OK);
574         }
575
576 /*
577  * set last read pointer
578  */
579 void cmd_slrp(char *new_ptr)
580 {
581         long newlr;
582
583         if (!(CC->logged_in)) {
584                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
585                 return;
586                 }
587
588         if (CC->curr_rm < 0) {
589                 cprintf("%d No current room.\n",ERROR);
590                 return;
591                 }
592
593         if (!strncasecmp(new_ptr,"highest",7)) {
594                 newlr = CC->quickroom.QRhighest;
595                 }
596         else {
597                 newlr = atol(new_ptr);
598                 }
599
600         lgetuser(&CC->usersupp, CC->curr_user);
601         CC->usersupp.lastseen[CC->curr_rm] = newlr;
602         lputuser(&CC->usersupp, CC->curr_user);
603         cprintf("%d %ld\n",OK,newlr);
604         }
605
606
607 /*
608  * INVT and KICK commands
609  */
610 void cmd_invt_kick(char *iuser, int op)
611                         /* user name */
612         {               /* 1 = invite, 0 = kick out */
613         struct usersupp USscratch;
614         char bbb[256];
615
616         if (!(CC->logged_in)) {
617                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
618                 return;
619                 }
620
621         if (CC->curr_rm < 0) {
622                 cprintf("%d No current room.\n",ERROR);
623                 return;
624                 }
625
626         if (is_room_aide()==0) {
627                 cprintf("%d Higher access required.\n",
628                         ERROR+HIGHER_ACCESS_REQUIRED);
629                 return;
630                 }
631
632         if ( (op==1) && ((CC->quickroom.QRflags&QR_PRIVATE)==0) ) {
633                 cprintf("%d Not a private room.\n",ERROR+NOT_HERE);
634                 return;
635                 }
636
637         if (lgetuser(&USscratch,iuser)!=0) {
638                 cprintf("%d No such user.\n",ERROR);
639                 return;
640                 }
641
642         if (op==1) {
643                 USscratch.generation[CC->curr_rm]=CC->quickroom.QRgen;
644                 USscratch.forget[CC->curr_rm]=(-1);
645                 }
646
647         if (op==0) {
648                 USscratch.generation[CC->curr_rm]=(-1);
649                 USscratch.forget[CC->curr_rm]=CC->quickroom.QRgen;
650                 }
651
652         lputuser(&USscratch,iuser);
653
654         /* post a message in Aide> saying what we just did */
655         sprintf(bbb,"%s %s %s> by %s",
656                 iuser,
657                 ((op == 1) ? "invited to" : "kicked out of"),
658                 CC->quickroom.QRname,
659                 CC->usersupp.fullname);
660         aide_message(bbb);
661
662         if ((op==0)&&((CC->quickroom.QRflags&QR_PRIVATE)==0)) {
663                 cprintf("%d Ok. (Not a private room, <Z>ap effect only)\n",OK);
664                 }
665         else {
666                 cprintf("%d Ok.\n",OK);
667                 }
668         return;
669         }
670
671
672 /*
673  * forget (Zap) the current room
674  */
675 void cmd_forg(void) {
676         if (!(CC->logged_in)) {
677                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
678                 return;
679                 }
680
681         if (CC->curr_rm < 0) {
682                 cprintf("%d No current room.\n",ERROR);
683                 return;
684                 }
685
686         if (CC->curr_rm < 3) {
687                 cprintf("%d You cannot forget this room.\n",ERROR+NOT_HERE);
688                 return;
689                 }
690
691         if (is_aide()) {
692                 cprintf("%d Aides cannot forget rooms.\n",ERROR);
693                 return;
694                 }
695
696         lgetuser(&CC->usersupp,CC->curr_user);
697         CC->usersupp.forget[CC->curr_rm] = CC->quickroom.QRgen;
698         CC->usersupp.generation[CC->curr_rm] = (-1);
699         lputuser(&CC->usersupp,CC->curr_user);
700         cprintf("%d Ok\n",OK);
701         CC->curr_rm = (-1);
702         }
703
704 /*
705  * Get Next Unregistered User
706  */
707 void cmd_gnur(void) {
708         struct cdbdata *cdbus;
709         struct usersupp usbuf;
710
711         if (!(CC->logged_in)) {
712                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
713                 return;
714                 }
715
716         if (CC->usersupp.axlevel < 6) {
717                 cprintf("%d Higher access required.\n",
718                         ERROR+HIGHER_ACCESS_REQUIRED);
719                 return;
720                 }
721
722         if ((CitControl.MMflags&MM_VALID)==0) {
723                 cprintf("%d There are no unvalidated users.\n",OK);
724                 return;
725                 }
726
727         /* There are unvalidated users.  Traverse the usersupp database,
728          * and return the first user we find that needs validation.
729          */
730         cdb_rewind(CDB_USERSUPP);
731         while (cdbus = cdb_next_item(CDB_USERSUPP), cdbus != NULL) {
732                 bzero(&usbuf, sizeof(struct usersupp));
733                 memcpy(&usbuf, cdbus->ptr,
734                         ( (cdbus->len > sizeof(struct usersupp)) ?
735                         sizeof(struct usersupp) : cdbus->len) );
736                 cdb_free(cdbus);
737                 if ((usbuf.flags & US_NEEDVALID)
738                    &&(usbuf.axlevel > 0)) {
739                         cprintf("%d %s\n",MORE_DATA,usbuf.fullname);
740                         return;
741                         }
742                 } 
743
744         /* If we get to this point, there are no more unvalidated users.
745          * Therefore we clear the "users need validation" flag.
746          */
747
748         begin_critical_section(S_CONTROL);
749         get_control();
750         CitControl.MMflags = CitControl.MMflags&(~MM_VALID);
751         put_control();
752         end_critical_section(S_CONTROL);
753         cprintf("%d *** End of registration.\n",OK);
754
755
756         }
757
758
759 /*
760  * get registration info for a user
761  */
762 void cmd_greg(char *who)
763 {
764         struct usersupp usbuf;
765         int a,b;
766         char pbuf[32];
767
768         if (!(CC->logged_in)) {
769                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
770                 return;
771                 }
772
773         if (!strcasecmp(who,"_SELF_")) strcpy(who,CC->curr_user);
774
775         if ((CC->usersupp.axlevel < 6) && (strcasecmp(who,CC->curr_user))) {
776                 cprintf("%d Higher access required.\n",
777                         ERROR+HIGHER_ACCESS_REQUIRED);
778                 return;
779                 }
780
781         if (getuser(&usbuf,who) != 0) {
782                 cprintf("%d '%s' not found.\n",ERROR+NO_SUCH_USER,who);
783                 return;
784                 }
785
786         cprintf("%d %s\n",LISTING_FOLLOWS,usbuf.fullname);
787         cprintf("%ld\n",usbuf.usernum);
788         cprintf("%s\n",usbuf.password);
789         cprintf("%s\n",usbuf.USname);
790         cprintf("%s\n",usbuf.USaddr);
791         cprintf("%s\n%s\n%s\n",
792                 usbuf.UScity,usbuf.USstate,usbuf.USzip);
793         strcpy(pbuf,usbuf.USphone);
794         usbuf.USphone[0]=0;
795         for (a=0; a<strlen(pbuf); ++a) {
796                 if ((pbuf[a]>='0')&&(pbuf[a]<='9')) {
797                         b=strlen(usbuf.USphone);
798                         usbuf.USphone[b]=pbuf[a];
799                         usbuf.USphone[b+1]=0;
800                         }
801                 }
802         while(strlen(usbuf.USphone)<10) {
803                 strcpy(pbuf,usbuf.USphone);
804                 strcpy(usbuf.USphone," ");
805                 strcat(usbuf.USphone,pbuf);
806                 }
807
808         cprintf("(%c%c%c) %c%c%c-%c%c%c%c\n",
809                 usbuf.USphone[0],usbuf.USphone[1],
810                 usbuf.USphone[2],usbuf.USphone[3],
811                 usbuf.USphone[4],usbuf.USphone[5],
812                 usbuf.USphone[6],usbuf.USphone[7],
813                 usbuf.USphone[8],usbuf.USphone[9]);
814
815         cprintf("%d\n",usbuf.axlevel);
816         cprintf("%s\n",usbuf.USemail);
817         cprintf("000\n");
818         }
819
820 /*
821  * validate a user
822  */
823 void cmd_vali(char *v_args)
824 {
825         char user[256];
826         int newax;
827         struct usersupp userbuf;
828
829         extract(user,v_args,0);
830         newax = extract_int(v_args,1);
831
832         if (!(CC->logged_in)) {
833                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
834                 return;
835                 }
836
837         if (CC->usersupp.axlevel < 6) {
838                 cprintf("%d Higher access required.\n",
839                         ERROR+HIGHER_ACCESS_REQUIRED);
840                 return;
841                 }
842
843         if (lgetuser(&userbuf,user)!=0) {
844                 cprintf("%d '%s' not found.\n",ERROR+NO_SUCH_USER,user);
845                 return;
846                 }
847
848         userbuf.axlevel = newax;
849         userbuf.flags = (userbuf.flags & ~US_NEEDVALID);
850
851         lputuser(&userbuf,user);
852
853         /* If the access level was set to zero, delete the user */
854         if (newax == 0) {
855                 if (purge_user(user)==0) {
856                         cprintf("%d %s Deleted.\n", OK, userbuf.fullname);
857                         return;
858                         }
859                 }
860
861         cprintf("%d ok\n",OK);
862         }
863
864
865
866 /* 
867  *  List users
868  */
869 void cmd_list(void) {
870         struct usersupp usbuf;
871         struct cdbdata *cdbus;
872
873         cdb_rewind(CDB_USERSUPP);
874         cprintf("%d \n",LISTING_FOLLOWS);
875
876         while(cdbus = cdb_next_item(CDB_USERSUPP), cdbus != NULL) {
877                 bzero(&usbuf, sizeof(struct usersupp));
878                 memcpy(&usbuf, cdbus->ptr,
879                         ( (cdbus->len > sizeof(struct usersupp)) ?
880                         sizeof(struct usersupp) : cdbus->len) );
881                 cdb_free(cdbus);
882
883             if (usbuf.axlevel > 0) {
884                 if ((CC->usersupp.axlevel>=6)
885                    ||((usbuf.flags&US_UNLISTED)==0)
886                    ||((CC->internal_pgm))) {
887                         cprintf("%s|%d|%ld|%ld|%d|%d|",
888                                 usbuf.fullname,
889                                 usbuf.axlevel,
890                                 usbuf.usernum,
891                                 usbuf.lastcall,
892                                 usbuf.timescalled,
893                                 usbuf.posted);
894                         if (CC->usersupp.axlevel >= 6) cprintf("%s",usbuf.password);
895                         cprintf("\n");
896                         }
897                     }
898                 }
899         cprintf("000\n");
900         }
901
902 /*
903  * enter registration info
904  */
905 void cmd_regi(void) {
906         int a,b,c;
907         char buf[256];
908
909         char tmpname[256];
910         char tmpaddr[256];
911         char tmpcity[256];
912         char tmpstate[256];
913         char tmpzip[256];
914         char tmpphone[256];
915         char tmpemail[256];
916
917         if (!(CC->logged_in)) {
918                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
919                 return;
920                 }
921
922         strcpy(tmpname,"");
923         strcpy(tmpaddr,"");
924         strcpy(tmpcity,"");
925         strcpy(tmpstate,"");
926         strcpy(tmpzip,"");
927         strcpy(tmpphone,"");
928         strcpy(tmpemail,"");
929
930         cprintf("%d Send registration...\n",SEND_LISTING);
931         a=0;
932         while (client_gets(buf), strcmp(buf,"000")) {
933                 if (a==0) strcpy(tmpname,buf);
934                 if (a==1) strcpy(tmpaddr,buf);
935                 if (a==2) strcpy(tmpcity,buf);
936                 if (a==3) strcpy(tmpstate,buf);
937                 if (a==4) {
938                         for (c=0; c<strlen(buf); ++c) {
939                                 if ((buf[c]>='0')&&(buf[c]<='9')) {
940                                         b=strlen(tmpzip);
941                                         tmpzip[b]=buf[c];
942                                         tmpzip[b+1]=0;
943                                         }
944                                 }
945                         }
946                 if (a==5) {
947                         for (c=0; c<strlen(buf); ++c) {
948                                 if ((buf[c]>='0')&&(buf[c]<='9')) {
949                                         b=strlen(tmpphone);
950                                         tmpphone[b]=buf[c];
951                                         tmpphone[b+1]=0;
952                                         }
953                                 }
954                         }
955                 if (a==6) strncpy(tmpemail,buf,31);
956                 ++a;
957                 }
958
959         tmpname[29]=0;
960         tmpaddr[24]=0;
961         tmpcity[14]=0;
962         tmpstate[2]=0;
963         tmpzip[9]=0;
964         tmpphone[10]=0;
965         tmpemail[31]=0;
966
967         lgetuser(&CC->usersupp,CC->curr_user);
968         strcpy(CC->usersupp.USname,tmpname);
969         strcpy(CC->usersupp.USaddr,tmpaddr);
970         strcpy(CC->usersupp.UScity,tmpcity);
971         strcpy(CC->usersupp.USstate,tmpstate);
972         strcpy(CC->usersupp.USzip,tmpzip);
973         strcpy(CC->usersupp.USphone,tmpphone);
974         strcpy(CC->usersupp.USemail,tmpemail);
975         CC->usersupp.flags=(CC->usersupp.flags|US_REGIS|US_NEEDVALID);
976         lputuser(&CC->usersupp,CC->curr_user);
977
978         /* set global flag calling for validation */
979         begin_critical_section(S_CONTROL);
980         get_control();
981         CitControl.MMflags = CitControl.MMflags | MM_VALID ;
982         put_control();
983         end_critical_section(S_CONTROL);
984         cprintf("%d *** End of registration.\n",OK);
985         }
986
987
988 /*
989  * assorted info we need to check at login
990  */
991 void cmd_chek(void) {
992         int mail = 0;
993         int regis = 0;
994         int vali = 0;
995         int a;
996         struct cdbdata *cdbmb;
997         long *mailbox;
998         int num_mails;
999         
1000
1001         if (!(CC->logged_in)) {
1002                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1003                 return;
1004                 }
1005
1006         getuser(&CC->usersupp,CC->curr_user); /* no lock is needed here */
1007         if ((REGISCALL!=0)&&((CC->usersupp.flags&US_REGIS)==0)) regis = 1;
1008
1009         if (CC->usersupp.axlevel >= 6) {
1010                 get_control();
1011                 if (CitControl.MMflags&MM_VALID) vali = 1;
1012                 }
1013
1014
1015         /* check for mail */
1016         mail = 0;
1017         cdbmb = cdb_fetch(CDB_MAILBOXES, &CC->usersupp.usernum, sizeof(long));
1018         if (cdbmb != NULL) {
1019                 num_mails = cdbmb->len / sizeof(long);
1020                 mailbox = (long *) cdbmb->ptr;
1021                 if (num_mails > 0) for (a=0; a<num_mails; ++a) {
1022                         if (mailbox[a] > (CC->usersupp.lastseen[1])) ++mail;
1023                         }
1024                 cdb_free(cdbmb);
1025                 }
1026
1027
1028         cprintf("%d %d|%d|%d\n",OK,mail,regis,vali);
1029         }
1030
1031
1032 /*
1033  * check to see if a user exists
1034  */
1035 void cmd_qusr(char *who)
1036 {
1037         struct usersupp usbuf;
1038
1039         if (getuser(&usbuf,who) == 0) {
1040                 cprintf("%d %s\n",OK,usbuf.fullname);
1041                 }
1042         else {
1043                 cprintf("%d No such user.\n",ERROR+NO_SUCH_USER);
1044                 }
1045         }
1046
1047
1048 /*
1049  * enter user bio
1050  */
1051 void cmd_ebio(void) {
1052         char buf[256];
1053         FILE *fp;
1054
1055         if (!(CC->logged_in)) {
1056                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1057                 return;
1058                 }
1059
1060         sprintf(buf,"./bio/%ld",CC->usersupp.usernum);
1061         fp = fopen(buf,"w");
1062         if (fp == NULL) {
1063                 cprintf("%d Cannot create file\n",ERROR);
1064                 return;
1065                 }
1066         cprintf("%d  \n",SEND_LISTING);
1067         while(client_gets(buf), strcmp(buf,"000")) {
1068                 fprintf(fp,"%s\n",buf);
1069                 }
1070         fclose(fp);
1071         }
1072
1073 /*
1074  * read user bio
1075  */
1076 void cmd_rbio(char *cmdbuf)
1077 {
1078         struct usersupp ruser;
1079         char buf[256];
1080         FILE *fp;
1081
1082         extract(buf,cmdbuf,0);
1083         if (getuser(&ruser,buf)!=0) {
1084                 cprintf("%d No such user.\n",ERROR+NO_SUCH_USER);
1085                 return;
1086                 }
1087         sprintf(buf,"./bio/%ld",ruser.usernum);
1088         
1089         fp = fopen(buf,"r");
1090         if (fp == NULL) {
1091                 cprintf("%d %s has no bio on file.\n",
1092                         ERROR+FILE_NOT_FOUND,ruser.fullname);
1093                 return;
1094                 }
1095         cprintf("%d  \n",LISTING_FOLLOWS);
1096         while (fgets(buf,256,fp)!=NULL) cprintf("%s",buf);
1097         fclose(fp);
1098         cprintf("000\n");
1099         }
1100
1101 /*
1102  * list of users who have entered bios
1103  */
1104 void cmd_lbio(void) {
1105         char buf[256];
1106         FILE *ls;
1107         struct usersupp usbuf;
1108
1109         ls=popen("cd ./bio; ls","r");
1110         if (ls==NULL) {
1111                 cprintf("%d Cannot open listing.\n",ERROR+FILE_NOT_FOUND);
1112                 return;
1113                 }
1114
1115         cprintf("%d\n",LISTING_FOLLOWS);
1116         while (fgets(buf,255,ls)!=NULL)
1117                 if (getuserbynumber(&usbuf,atol(buf))==0)
1118                         cprintf("%s\n",usbuf.fullname);
1119         pclose(ls);
1120         cprintf("000\n");
1121         }
1122
1123
1124 /*
1125  * Administrative Get User Parameters
1126  */
1127 void cmd_agup(char *cmdbuf) {
1128         struct usersupp usbuf;
1129         char requested_user[256];
1130
1131         if ( (CC->internal_pgm==0)
1132            && ( (CC->logged_in == 0) || (is_aide()==0) ) ) {
1133                 cprintf("%d Higher access required.\n", 
1134                         ERROR + HIGHER_ACCESS_REQUIRED);
1135                 return;
1136                 }
1137
1138         extract(requested_user, cmdbuf, 0);
1139         if (getuser(&usbuf, requested_user) != 0) {
1140                 cprintf("%d No such user.\n", ERROR + NO_SUCH_USER);
1141                 return;
1142                 }
1143
1144         cprintf("%d %s|%s|%u|%d|%d|%d|%ld\n", 
1145                 OK,
1146                 usbuf.fullname,
1147                 usbuf.password,
1148                 usbuf.flags,
1149                 usbuf.timescalled,
1150                 usbuf.posted,
1151                 (int)usbuf.axlevel,
1152                 usbuf.usernum);
1153
1154         }
1155
1156
1157
1158 /*
1159  * Administrative Set User Parameters
1160  */
1161 void cmd_asup(char *cmdbuf) {
1162         struct usersupp usbuf;
1163         char requested_user[256];
1164         int np;
1165         int newax;
1166         
1167         if ( (CC->internal_pgm==0)
1168            && ( (CC->logged_in == 0) || (is_aide()==0) ) ) {
1169                 cprintf("%d Higher access required.\n", 
1170                         ERROR + HIGHER_ACCESS_REQUIRED);
1171                 return;
1172                 }
1173
1174         extract(requested_user, cmdbuf, 0);
1175         if (lgetuser(&usbuf, requested_user) != 0) {
1176                 cprintf("%d No such user.\n", ERROR + NO_SUCH_USER);
1177                 return;
1178                 }
1179
1180         np = num_parms(cmdbuf);
1181         if (np > 1) extract(usbuf.password, cmdbuf, 1);
1182         if (np > 2) usbuf.flags = extract_int(cmdbuf, 2);
1183         if (np > 3) usbuf.timescalled = extract_int(cmdbuf, 3);
1184         if (np > 4) usbuf.posted = extract_int(cmdbuf, 4);
1185         if (np > 5) {
1186                 newax = extract_int(cmdbuf, 5);
1187                 if ((newax >=0) && (newax <= 6)) {
1188                         usbuf.axlevel = extract_int(cmdbuf, 5);
1189                         }
1190                 }
1191
1192         lputuser(&usbuf, requested_user);
1193         if (usbuf.axlevel == 0) {
1194                 if (purge_user(requested_user)==0) {
1195                         cprintf("%d %s deleted.\n", OK, requested_user);
1196                         }
1197                 }
1198         cprintf("%d Ok\n", OK);
1199         }