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