|
|
1.1 root 1: /* userdat.c */
2:
3: /* Synchronet user data-related routines (exported) */
4:
5: /* $Id: userdat.c,v 1.101 2006/12/29 09:00:59 rswindell Exp $ */
6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: #include "sbbs.h"
39: #include "cmdshell.h"
40: #ifndef USHRT_MAX
41: #define USHRT_MAX ((unsigned short)~0)
42: #endif
43:
44: /* convenient space-saving global variables */
45: char* crlf="\r\n";
46: char* nulstr="";
47:
48: #define VALID_CFG(cfg) (cfg!=NULL && cfg->size==sizeof(scfg_t))
49:
50: /****************************************************************************/
51: /* Looks for a perfect match amoung all usernames (not deleted users) */
52: /* Makes dots and underscores synomynous with spaces for comparisions */
53: /* Returns the number of the perfect matched username or 0 if no match */
54: /****************************************************************************/
55: uint DLLCALL matchuser(scfg_t* cfg, char *name, BOOL sysop_alias)
56: {
57: int file,c;
58: char* p;
59: char dat[LEN_ALIAS+2];
60: char str[256];
61: ulong l,length;
62: FILE* stream;
63:
64: if(!VALID_CFG(cfg) || name==NULL)
65: return(0);
66:
67: if(sysop_alias &&
68: (!stricmp(name,"SYSOP") || !stricmp(name,"POSTMASTER") || !stricmp(name,cfg->sys_id)))
69: return(1);
70:
71: sprintf(str,"%suser/name.dat",cfg->data_dir);
72: if((file=nopen(str,O_RDONLY))==-1)
73: return(0);
74: length=filelength(file);
75: if((stream=fdopen(file,"rb"))==NULL)
76: return(0);
77: for(l=0;l<length;l+=LEN_ALIAS+2) {
78: fread(dat,sizeof(dat),1,stream);
79: for(c=0;c<LEN_ALIAS;c++)
80: if(dat[c]==ETX) break;
81: dat[c]=0;
82: if(!stricmp(dat,name))
83: break;
84: /* convert dots to spaces */
85: strcpy(str,dat);
86: REPLACE_CHARS(str,'.',' ',p);
87: if(!stricmp(str,name))
88: break;
89: /* convert spaces to dots */
90: strcpy(str,dat);
91: REPLACE_CHARS(str,' ','.',p);
92: if(!stricmp(str,name))
93: break;
94: /* convert dots to underscores */
95: strcpy(str,dat);
96: REPLACE_CHARS(str,'.','_',p);
97: if(!stricmp(str,name))
98: break;
99: /* convert underscores to dots */
100: strcpy(str,dat);
101: REPLACE_CHARS(str,'_','.',p);
102: if(!stricmp(str,name))
103: break;
104: /* convert spaces to underscores */
105: strcpy(str,dat);
106: REPLACE_CHARS(str,' ','_',p);
107: if(!stricmp(str,name))
108: break;
109: /* convert underscores to spaces */
110: strcpy(str,dat);
111: REPLACE_CHARS(str,'_',' ',p);
112: if(!stricmp(str,name))
113: break;
114: }
115: fclose(stream);
116: if(l<length)
117: return((l/(LEN_ALIAS+2))+1);
118: return(0);
119: }
120:
121: /****************************************************************************/
122: uint DLLCALL total_users(scfg_t* cfg)
123: {
124: char str[MAX_PATH+1];
125: uint total_users=0;
126: int file;
127: long l,length;
128:
129: if(!VALID_CFG(cfg))
130: return(0);
131:
132: sprintf(str,"%suser/user.dat", cfg->data_dir);
133: if((file=nopen(str,O_RDONLY|O_DENYNONE))==-1)
134: return(0);
135: length=filelength(file);
136: for(l=0;l<length;l+=U_LEN) {
137: lseek(file,l+U_MISC,SEEK_SET);
138: if(read(file,str,8)!=8)
139: continue;
140: getrec(str,0,8,str);
141: if(ahtoul(str)&(DELETED|INACTIVE))
142: continue;
143: total_users++;
144: }
145: close(file);
146: return(total_users);
147: }
148:
149:
150: /****************************************************************************/
151: /* Returns the number of the last user in user.dat (deleted ones too) */
152: /****************************************************************************/
153: uint DLLCALL lastuser(scfg_t* cfg)
154: {
155: char str[256];
156: long length;
157:
158: if(!VALID_CFG(cfg))
159: return(0);
160:
161: sprintf(str,"%suser/user.dat", cfg->data_dir);
162: if((length=flength(str))>0)
163: return((uint)(length/U_LEN));
164: return(0);
165: }
166:
167: /****************************************************************************/
168: /* Deletes last user record in user.dat */
169: /****************************************************************************/
170: BOOL DLLCALL del_lastuser(scfg_t* cfg)
171: {
172: char str[256];
173: int file;
174: long length;
175:
176: if(!VALID_CFG(cfg))
177: return(FALSE);
178:
179: sprintf(str,"%suser/user.dat", cfg->data_dir);
180: if((file=nopen(str,O_RDWR|O_DENYNONE))==-1)
181: return(FALSE);
182: length=filelength(file);
183: if(length<U_LEN) {
184: close(file);
185: return(FALSE);
186: }
187: chsize(file,length-U_LEN);
188: close(file);
189: return(TRUE);
190: }
191:
192:
193: /****************************************************************************/
194: /* Fills the structure 'user' with info for user.number from user.dat */
195: /* Called from functions useredit, waitforcall and main_sec */
196: /****************************************************************************/
197: int DLLCALL getuserdat(scfg_t* cfg, user_t *user)
198: {
199: char userdat[U_LEN+1],str[U_LEN+1],tmp[64];
200: int i,file;
201: unsigned user_number;
202:
203: if(user==NULL)
204: return(-1);
205:
206: user_number=user->number;
207: memset(user,0,sizeof(user_t));
208:
209: if(!VALID_CFG(cfg) || user_number<1)
210: return(-1);
211:
212: sprintf(userdat,"%suser/user.dat",cfg->data_dir);
213: if((file=nopen(userdat,O_RDONLY|O_DENYNONE))==-1)
214: return(errno);
215:
216: if(user_number > (unsigned)(filelength(file)/U_LEN)) {
217: close(file);
218: return(-1); /* no such user record */
219: }
220: lseek(file,(long)((long)(user_number-1)*U_LEN),SEEK_SET);
221: i=0;
222: while(i<LOOP_NODEDAB
223: && lock(file,(long)((long)(user_number-1)*U_LEN),U_LEN)==-1) {
224: if(i)
225: mswait(100);
226: i++;
227: }
228:
229: if(i>=LOOP_NODEDAB) {
230: close(file);
231: return(-2);
232: }
233:
234: if(read(file,userdat,U_LEN)!=U_LEN) {
235: unlock(file,(long)((long)(user_number-1)*U_LEN),U_LEN);
236: close(file);
237: return(-3);
238: }
239:
240: unlock(file,(long)((long)(user_number-1)*U_LEN),U_LEN);
241: close(file);
242: /* order of these function calls is irrelevant */
243: getrec(userdat,U_ALIAS,LEN_ALIAS,user->alias);
244: getrec(userdat,U_NAME,LEN_NAME,user->name);
245: getrec(userdat,U_HANDLE,LEN_HANDLE,user->handle);
246: getrec(userdat,U_NOTE,LEN_NOTE,user->note);
247: getrec(userdat,U_COMP,LEN_COMP,user->comp);
248: getrec(userdat,U_COMMENT,LEN_COMMENT,user->comment);
249: getrec(userdat,U_NETMAIL,LEN_NETMAIL,user->netmail);
250: getrec(userdat,U_ADDRESS,LEN_ADDRESS,user->address);
251: getrec(userdat,U_LOCATION,LEN_LOCATION,user->location);
252: getrec(userdat,U_ZIPCODE,LEN_ZIPCODE,user->zipcode);
253: getrec(userdat,U_PASS,LEN_PASS,user->pass);
254: getrec(userdat,U_PHONE,LEN_PHONE,user->phone);
255: getrec(userdat,U_BIRTH,LEN_BIRTH,user->birth);
256: getrec(userdat,U_MODEM,LEN_MODEM,user->modem);
257: getrec(userdat,U_LASTON,8,str); user->laston=ahtoul(str);
258: getrec(userdat,U_FIRSTON,8,str); user->firston=ahtoul(str);
259: getrec(userdat,U_EXPIRE,8,str); user->expire=ahtoul(str);
260: getrec(userdat,U_PWMOD,8,str); user->pwmod=ahtoul(str);
261: getrec(userdat,U_NS_TIME,8,str);
262: user->ns_time=ahtoul(str);
263: if(user->ns_time<0x20000000L)
264: user->ns_time=user->laston; /* Fix for v2.00->v2.10 */
265: getrec(userdat,U_LOGONTIME,8,str); user->logontime=ahtoul(str);
266:
267: getrec(userdat,U_LOGONS,5,str); user->logons=atoi(str);
268: getrec(userdat,U_LTODAY,5,str); user->ltoday=atoi(str);
269: getrec(userdat,U_TIMEON,5,str); user->timeon=atoi(str);
270: getrec(userdat,U_TEXTRA,5,str); user->textra=atoi(str);
271: getrec(userdat,U_TTODAY,5,str); user->ttoday=atoi(str);
272: getrec(userdat,U_TLAST,5,str); user->tlast=atoi(str);
273: getrec(userdat,U_POSTS,5,str); user->posts=atoi(str);
274: getrec(userdat,U_EMAILS,5,str); user->emails=atoi(str);
275: getrec(userdat,U_FBACKS,5,str); user->fbacks=atoi(str);
276: getrec(userdat,U_ETODAY,5,str); user->etoday=atoi(str);
277: getrec(userdat,U_PTODAY,5,str); user->ptoday=atoi(str);
278: getrec(userdat,U_ULB,10,str); user->ulb=atol(str);
279: getrec(userdat,U_ULS,5,str); user->uls=atoi(str);
280: getrec(userdat,U_DLB,10,str); user->dlb=atol(str);
281: getrec(userdat,U_DLS,5,str); user->dls=atoi(str);
282: getrec(userdat,U_CDT,10,str); user->cdt=atol(str);
283: getrec(userdat,U_MIN,10,str); user->min=atol(str);
284: getrec(userdat,U_LEVEL,2,str); user->level=atoi(str);
285: getrec(userdat,U_FLAGS1,8,str); user->flags1=ahtoul(str);
286: getrec(userdat,U_FLAGS2,8,str); user->flags2=ahtoul(str);
287: getrec(userdat,U_FLAGS3,8,str); user->flags3=ahtoul(str);
288: getrec(userdat,U_FLAGS4,8,str); user->flags4=ahtoul(str);
289: getrec(userdat,U_EXEMPT,8,str); user->exempt=ahtoul(str);
290: getrec(userdat,U_REST,8,str); user->rest=ahtoul(str);
291: getrec(userdat,U_ROWS,2,str); user->rows=atoi(str);
292: if(user->rows && user->rows<10)
293: user->rows=10;
294: user->sex=userdat[U_SEX];
295: if(!user->sex)
296: user->sex=' '; /* fix for v1b04 that could save as 0 */
297: user->prot=userdat[U_PROT];
298: if(user->prot<' ')
299: user->prot=' ';
300: getrec(userdat,U_MISC,8,str); user->misc=ahtoul(str);
301: if(user->rest&FLAG('Q'))
302: user->misc&=~SPIN;
303:
304: getrec(userdat,U_LEECH,2,str);
305: user->leech=(uchar)ahtoul(str);
306: getrec(userdat,U_CURSUB,sizeof(user->cursub)-1,user->cursub);
307: getrec(userdat,U_CURDIR,sizeof(user->curdir)-1,user->curdir);
308: getrec(userdat,U_CURXTRN,8,user->curxtrn);
309:
310: getrec(userdat,U_FREECDT,10,str);
311: user->freecdt=atol(str);
312:
313: getrec(userdat,U_XEDIT,8,str);
314: for(i=0;i<cfg->total_xedits;i++)
315: if(!stricmp(str,cfg->xedit[i]->code) && chk_ar(cfg,cfg->xedit[i]->ar,user))
316: break;
317: user->xedit=i+1;
318: if(user->xedit>cfg->total_xedits)
319: user->xedit=0;
320:
321: getrec(userdat,U_SHELL,8,str);
322: for(i=0;i<cfg->total_shells;i++)
323: if(!stricmp(str,cfg->shell[i]->code))
324: break;
325: if(i==cfg->total_shells)
326: i=0;
327: user->shell=i;
328:
329: getrec(userdat,U_QWK,8,str);
330: if(str[0]<' ') { /* v1c, so set defaults */
331: if(user->rest&FLAG('Q'))
332: user->qwk=QWK_DEFAULT|QWK_RETCTLA;
333: else
334: user->qwk=QWK_DEFAULT;
335: }
336: else
337: user->qwk=ahtoul(str);
338:
339: getrec(userdat,U_TMPEXT,3,user->tmpext);
340: if((!user->tmpext[0] || !strcmp(user->tmpext,"0")) && cfg->total_fcomps)
341: strcpy(user->tmpext,cfg->fcomp[0]->ext); /* For v1x to v2x conversion */
342:
343: getrec(userdat,U_CHAT,8,str);
344: user->chat=ahtoul(str);
345:
346: /* Reset daily stats if not logged on today */
347: unixtodstr(cfg, time(NULL),str);
348: unixtodstr(cfg, user->laston,tmp);
349: if(strcmp(str,tmp) && user->ltoday)
350: resetdailyuserdat(cfg,user);
351:
352: #if 0 /* removed 01/19/00 Why? ToDo */
353: if(useron.number==user_number) {
354: if(user!=&useron)
355: useron=*user;
356:
357: if(online) {
358:
359: #if 0 /* legacy? ToDo */
360: getusrdirs();
361: getusrsubs();
362: #endif
363: if(user->misc&AUTOTERM) { /* was useron.misc (01/19/00) */
364: user->misc&=~(ANSI|RIP|WIP|HTML);
365: user->misc|=autoterm;
366: }
367: }
368: }
369: #endif
370: user->number=user_number; /* Signal of success */
371:
372: return(0);
373: }
374:
375: /****************************************************************************/
376: /* Writes into user.number's slot in user.dat data in structure 'user' */
377: /* Called from functions newuser, useredit and main */
378: /****************************************************************************/
379: int DLLCALL putuserdat(scfg_t* cfg, user_t* user)
380: {
381: int i,file;
382: char userdat[U_LEN],str[MAX_PATH+1];
383: node_t node;
384:
385: if(user==NULL)
386: return(-1);
387:
388: if(!VALID_CFG(cfg) || user->number<1)
389: return(-1);
390:
391: memset(userdat,ETX,U_LEN);
392: putrec(userdat,U_ALIAS,LEN_ALIAS+5,user->alias);
393: putrec(userdat,U_NAME,LEN_NAME,user->name);
394: putrec(userdat,U_HANDLE,LEN_HANDLE,user->handle);
395: putrec(userdat,U_HANDLE+LEN_HANDLE,2,crlf);
396:
397: putrec(userdat,U_NOTE,LEN_NOTE,user->note);
398: putrec(userdat,U_COMP,LEN_COMP,user->comp);
399: putrec(userdat,U_COMP+LEN_COMP,2,crlf);
400:
401: putrec(userdat,U_COMMENT,LEN_COMMENT,user->comment);
402: putrec(userdat,U_COMMENT+LEN_COMMENT,2,crlf);
403:
404: putrec(userdat,U_NETMAIL,LEN_NETMAIL,user->netmail);
405: putrec(userdat,U_NETMAIL+LEN_NETMAIL,2,crlf);
406:
407: putrec(userdat,U_ADDRESS,LEN_ADDRESS,user->address);
408: putrec(userdat,U_LOCATION,LEN_LOCATION,user->location);
409: putrec(userdat,U_ZIPCODE,LEN_ZIPCODE,user->zipcode);
410: putrec(userdat,U_ZIPCODE+LEN_ZIPCODE,2,crlf);
411:
412: putrec(userdat,U_PASS,LEN_PASS,user->pass);
413: putrec(userdat,U_PHONE,LEN_PHONE,user->phone);
414: putrec(userdat,U_BIRTH,LEN_BIRTH,user->birth);
415: putrec(userdat,U_MODEM,LEN_MODEM,user->modem);
416: putrec(userdat,U_LASTON,8,ultoa(user->laston,str,16));
417: putrec(userdat,U_FIRSTON,8,ultoa(user->firston,str,16));
418: putrec(userdat,U_EXPIRE,8,ultoa(user->expire,str,16));
419: putrec(userdat,U_PWMOD,8,ultoa(user->pwmod,str,16));
420: putrec(userdat,U_PWMOD+8,2,crlf);
421:
422: putrec(userdat,U_LOGONS,5,ultoa(user->logons,str,10));
423: putrec(userdat,U_LTODAY,5,ultoa(user->ltoday,str,10));
424: putrec(userdat,U_TIMEON,5,ultoa(user->timeon,str,10));
425: putrec(userdat,U_TEXTRA,5,ultoa(user->textra,str,10));
426: putrec(userdat,U_TTODAY,5,ultoa(user->ttoday,str,10));
427: putrec(userdat,U_TLAST,5,ultoa(user->tlast,str,10));
428: putrec(userdat,U_POSTS,5,ultoa(user->posts,str,10));
429: putrec(userdat,U_EMAILS,5,ultoa(user->emails,str,10));
430: putrec(userdat,U_FBACKS,5,ultoa(user->fbacks,str,10));
431: putrec(userdat,U_ETODAY,5,ultoa(user->etoday,str,10));
432: putrec(userdat,U_PTODAY,5,ultoa(user->ptoday,str,10));
433: putrec(userdat,U_PTODAY+5,2,crlf);
434:
435: putrec(userdat,U_ULB,10,ultoa(user->ulb,str,10));
436: putrec(userdat,U_ULS,5,ultoa(user->uls,str,10));
437: putrec(userdat,U_DLB,10,ultoa(user->dlb,str,10));
438: putrec(userdat,U_DLS,5,ultoa(user->dls,str,10));
439: putrec(userdat,U_CDT,10,ultoa(user->cdt,str,10));
440: putrec(userdat,U_MIN,10,ultoa(user->min,str,10));
441: putrec(userdat,U_MIN+10,2,crlf);
442:
443: putrec(userdat,U_LEVEL,2,ultoa(user->level,str,10));
444: putrec(userdat,U_FLAGS1,8,ultoa(user->flags1,str,16));
445: putrec(userdat,U_TL,2,nulstr); /* unused */
446: putrec(userdat,U_FLAGS2,8,ultoa(user->flags2,str,16));
447: putrec(userdat,U_EXEMPT,8,ultoa(user->exempt,str,16));
448: putrec(userdat,U_REST,8,ultoa(user->rest,str,16));
449: putrec(userdat,U_REST+8,2,crlf);
450:
451: putrec(userdat,U_ROWS,2,ultoa(user->rows,str,10));
452: userdat[U_SEX]=user->sex;
453: userdat[U_PROT]=user->prot;
454: putrec(userdat,U_MISC,8,ultoa(user->misc,str,16));
455: putrec(userdat,U_LEECH,2,ultoa(user->leech,str,16));
456:
457: putrec(userdat,U_CURSUB,sizeof(user->cursub)-1,user->cursub);
458: putrec(userdat,U_CURDIR,sizeof(user->curdir)-1,user->curdir);
459: putrec(userdat,U_CURXTRN,8,user->curxtrn);
460: putrec(userdat,U_CURXTRN+8,2,crlf);
461:
462: putrec(userdat,U_XFER_CMD+LEN_XFER_CMD,2,crlf);
463:
464: putrec(userdat,U_MAIL_CMD+LEN_MAIL_CMD,2,crlf);
465:
466: putrec(userdat,U_FREECDT,10,ultoa(user->freecdt,str,10));
467:
468: putrec(userdat,U_FLAGS3,8,ultoa(user->flags3,str,16));
469: putrec(userdat,U_FLAGS4,8,ultoa(user->flags4,str,16));
470:
471: if(user->xedit)
472: putrec(userdat,U_XEDIT,8,cfg->xedit[user->xedit-1]->code);
473: else
474: putrec(userdat,U_XEDIT,8,nulstr);
475:
476: putrec(userdat,U_SHELL,8,cfg->shell[user->shell]->code);
477:
478: putrec(userdat,U_QWK,8,ultoa(user->qwk,str,16));
479: putrec(userdat,U_TMPEXT,3,user->tmpext);
480: putrec(userdat,U_CHAT,8,ultoa(user->chat,str,16));
481: putrec(userdat,U_NS_TIME,8,ultoa(user->ns_time,str,16));
482: putrec(userdat,U_LOGONTIME,8,ultoa(user->logontime,str,16));
483:
484: putrec(userdat,U_UNUSED,U_LEN-(U_UNUSED)-2,crlf);
485: putrec(userdat,U_UNUSED+(U_LEN-(U_UNUSED)-2),2,crlf);
486:
487: sprintf(str,"%suser/user.dat", cfg->data_dir);
488: if((file=nopen(str,O_RDWR|O_CREAT|O_DENYNONE))==-1) {
489: return(errno);
490: }
491:
492: if(filelength(file)<((long)user->number-1)*U_LEN) {
493: close(file);
494: return(-4);
495: }
496:
497: lseek(file,(long)((long)((long)user->number-1)*U_LEN),SEEK_SET);
498:
499: i=0;
500: while(i<LOOP_NODEDAB
501: && lock(file,(long)((long)(user->number-1)*U_LEN),U_LEN)==-1) {
502: if(i)
503: mswait(100);
504: i++;
505: }
506:
507: if(i>=LOOP_NODEDAB) {
508: close(file);
509: return(-2);
510: }
511:
512: if(write(file,userdat,U_LEN)!=U_LEN) {
513: unlock(file,(long)((long)(user->number-1)*U_LEN),U_LEN);
514: close(file);
515: return(-3);
516: }
517: unlock(file,(long)((long)(user->number-1)*U_LEN),U_LEN);
518: close(file);
519: for(i=1;i<=cfg->sys_nodes;i++) { /* instant user data update */
520: if(i==cfg->node_num)
521: continue;
522: getnodedat(cfg, i,&node,NULL);
523: if(node.useron==user->number && (node.status==NODE_INUSE
524: || node.status==NODE_QUIET)) {
525: getnodedat(cfg, i,&node,&file);
526: node.misc|=NODE_UDAT;
527: putnodedat(cfg, i,&node,file);
528: break;
529: }
530: }
531: return(0);
532: }
533:
534:
535: /****************************************************************************/
536: /* Returns the username in 'str' that corresponds to the 'usernumber' */
537: /* Called from functions everywhere */
538: /****************************************************************************/
539: char* DLLCALL username(scfg_t* cfg, int usernumber, char *name)
540: {
541: char str[256];
542: int c;
543: int file;
544:
545: if(name==NULL)
546: return(NULL);
547:
548: if(!VALID_CFG(cfg) || usernumber<1) {
549: name[0]=0;
550: return(name);
551: }
552: sprintf(str,"%suser/name.dat",cfg->data_dir);
553: if(flength(str)<1L) {
554: name[0]=0;
555: return(name);
556: }
557: if((file=nopen(str,O_RDONLY))==-1) {
558: name[0]=0;
559: return(name);
560: }
561: if(filelength(file)<(long)((long)usernumber*(LEN_ALIAS+2))) {
562: close(file);
563: name[0]=0;
564: return(name);
565: }
566: lseek(file,(long)((long)(usernumber-1)*(LEN_ALIAS+2)),SEEK_SET);
567: read(file,name,LEN_ALIAS);
568: close(file);
569: for(c=0;c<LEN_ALIAS;c++)
570: if(name[c]==ETX) break;
571: name[c]=0;
572: if(!c)
573: strcpy(name,"DELETED USER");
574: return(name);
575: }
576:
577: /****************************************************************************/
578: /* Puts 'name' into slot 'number' in user/name.dat */
579: /****************************************************************************/
580: int DLLCALL putusername(scfg_t* cfg, int number, char *name)
581: {
582: char str[256];
583: int file;
584: int wr;
585: long length;
586: uint total_users;
587:
588: if(!VALID_CFG(cfg) || name==NULL || number<1)
589: return(-1);
590:
591: sprintf(str,"%suser/name.dat", cfg->data_dir);
592: if((file=nopen(str,O_RDWR|O_CREAT))==-1)
593: return(errno);
594: length=filelength(file);
595:
596: /* Truncate corrupted name.dat */
597: total_users=lastuser(cfg);
598: if((uint)(length/(LEN_ALIAS+2))>total_users)
599: chsize(file,total_users*(LEN_ALIAS+2));
600:
601: if(length && length%(LEN_ALIAS+2)) {
602: close(file);
603: return(-3);
604: }
605: if(length<(((long)number-1)*(LEN_ALIAS+2))) {
606: sprintf(str,"%*s",LEN_ALIAS,nulstr);
607: memset(str,ETX,LEN_ALIAS);
608: strcat(str,crlf);
609: lseek(file,0L,SEEK_END);
610: while(filelength(file)<((long)number*(LEN_ALIAS+2)))
611: write(file,str,(LEN_ALIAS+2));
612: }
613: lseek(file,(long)(((long)number-1)*(LEN_ALIAS+2)),SEEK_SET);
614: putrec(str,0,LEN_ALIAS,name);
615: putrec(str,LEN_ALIAS,2,crlf);
616: wr=write(file,str,LEN_ALIAS+2);
617: close(file);
618:
619: if(wr!=LEN_ALIAS+2)
620: return(errno);
621: return(0);
622: }
623:
624: /****************************************************************************/
625: /* Returns the age derived from the string 'birth' in the format MM/DD/YY */
626: /****************************************************************************/
627: char DLLCALL getage(scfg_t* cfg, char *birth)
628: {
629: char age;
630: struct tm tm;
631: time_t now;
632:
633: if(!VALID_CFG(cfg) || birth==NULL)
634: return(0);
635:
636: if(!atoi(birth) || !atoi(birth+3)) /* Invalid */
637: return(0);
638:
639: now=time(NULL);
640: if(localtime_r(&now,&tm)==NULL)
641: return(0);
642: age=(tm.tm_year)-(((birth[6]&0xf)*10)+(birth[7]&0xf));
643: if(age>105)
644: age-=105;
645: tm.tm_mon++; /* convert to 1 based */
646: if(cfg->sys_misc&SM_EURODATE) { /* DD/MM/YY format */
647: if(atoi(birth)>31 || atoi(birth+3)>12)
648: return(0);
649: if(((birth[3]&0xf)*10)+(birth[4]&0xf)>tm.tm_mon ||
650: (((birth[3]&0xf)*10)+(birth[4]&0xf)==tm.tm_mon &&
651: ((birth[0]&0xf)*10)+(birth[1]&0xf)>tm.tm_mday))
652: age--;
653: } else { /* MM/DD/YY format */
654: if(atoi(birth)>12 || atoi(birth+3)>31)
655: return(0);
656: if(((birth[0]&0xf)*10)+(birth[1]&0xf)>tm.tm_mon ||
657: (((birth[0]&0xf)*10)+(birth[1]&0xf)==tm.tm_mon &&
658: ((birth[3]&0xf)*10)+(birth[4]&0xf)>tm.tm_mday))
659: age--;
660: }
661: if(age<0)
662: return(0);
663: return(age);
664: }
665:
666:
667: /****************************************************************************/
668: /* Reads the data for node number 'number' into the structure 'node' */
669: /* from node.dab */
670: /****************************************************************************/
671: int DLLCALL getnodedat(scfg_t* cfg, uint number, node_t *node, int* fdp)
672: {
673: char str[MAX_PATH+1];
674: int rd;
675: int count=0;
676: int file;
677:
678: if(fdp!=NULL)
679: *fdp=-1;
680:
681: if(!VALID_CFG(cfg)
682: || node==NULL || number<1 || number>cfg->sys_nodes)
683: return(-1);
684:
685: memset(node,0,sizeof(node_t));
686: sprintf(str,"%snode.dab",cfg->ctrl_dir);
687: if((file=nopen(str,O_RDWR|O_DENYNONE))==-1)
688: return(errno);
689:
690: if(filelength(file)>=(long)(number*sizeof(node_t))) {
691: number--; /* make zero based */
692: for(count=0;count<LOOP_NODEDAB;count++) {
693: if(count)
694: mswait(100);
695: lseek(file,(long)number*sizeof(node_t),SEEK_SET);
696: if(fdp!=NULL
697: && lock(file,(long)number*sizeof(node_t),sizeof(node_t))!=0)
698: continue;
699: rd=read(file,node,sizeof(node_t));
700: if(fdp==NULL || rd!=sizeof(node_t))
701: unlock(file,(long)number*sizeof(node_t),sizeof(node_t));
702: if(rd==sizeof(node_t))
703: break;
704: }
705: }
706:
707: if(fdp==NULL || count==LOOP_NODEDAB)
708: close(file);
709: else
710: *fdp=file;
711:
712: if(count==LOOP_NODEDAB)
713: return(-2);
714:
715: return(0);
716: }
717:
718: /****************************************************************************/
719: /* Write the data from the structure 'node' into node.dab */
720: /****************************************************************************/
721: int DLLCALL putnodedat(scfg_t* cfg, uint number, node_t* node, int file)
722: {
723: size_t wr=0;
724: int wrerr=0;
725: int attempts;
726:
727: if(!VALID_CFG(cfg)
728: || node==NULL || number<1 || number>cfg->sys_nodes || file<0) {
729: close(file);
730: return(-1);
731: }
732:
733: number--; /* make zero based */
734: for(attempts=0;attempts<10;attempts++) {
735: lseek(file,(long)number*sizeof(node_t),SEEK_SET);
736: if((wr=write(file,node,sizeof(node_t)))==sizeof(node_t))
737: break;
738: wrerr=errno; /* save write error */
739: mswait(100);
740: }
741: unlock(file,(long)number*sizeof(node_t),sizeof(node_t));
742: close(file);
743:
744: if(wr!=sizeof(node_t))
745: return(wrerr);
746: return(0);
747: }
748:
749: /****************************************************************************/
750: /* Packs the password 'pass' into 5bit ASCII inside node_t. 32bits in */
751: /* node.extaux, and the other 8bits in the upper byte of node.aux */
752: /****************************************************************************/
753: void DLLCALL packchatpass(char *pass, node_t *node)
754: {
755: char bits;
756: int i,j;
757:
758: if(pass==NULL || node==NULL)
759: return;
760:
761: node->aux&=~0xff00; /* clear the password */
762: node->extaux=0L;
763: if((j=strlen(pass))==0) /* there isn't a password */
764: return;
765: node->aux|=(int)((pass[0]-64)<<8); /* 1st char goes in low 5bits of aux */
766: if(j==1) /* password is only one char, we're done */
767: return;
768: node->aux|=(int)((pass[1]-64)<<13); /* low 3bits of 2nd char go in aux */
769: node->extaux|=(long)((pass[1]-64)>>3); /* high 2bits of 2nd char go extaux */
770: bits=2;
771: for(i=2;i<j;i++) { /* now process the 3rd char through the last */
772: node->extaux|=(long)((long)(pass[i]-64)<<bits);
773: bits+=5;
774: }
775: }
776:
777: /****************************************************************************/
778: /* Unpacks the password 'pass' from the 5bit ASCII inside node_t. 32bits in */
779: /* node.extaux, and the other 8bits in the upper byte of node.aux */
780: /****************************************************************************/
781: char* DLLCALL unpackchatpass(char *pass, node_t* node)
782: {
783: char bits;
784: int i;
785:
786: if(pass==NULL || node==NULL)
787: return(NULL);
788:
789: pass[0]=(node->aux&0x1f00)>>8;
790: pass[1]=(char)(((node->aux&0xe000)>>13)|((node->extaux&0x3)<<3));
791: bits=2;
792: for(i=2;i<8;i++) {
793: pass[i]=(char)((node->extaux>>bits)&0x1f);
794: bits+=5;
795: }
796: pass[8]=0;
797: for(i=0;i<8;i++)
798: if(pass[i])
799: pass[i]+=64;
800: return(pass);
801: }
802:
803: char* DLLCALL nodestatus(scfg_t* cfg, node_t* node, char* buf, size_t buflen)
804: {
805: char str[256];
806: char* mer;
807: int hour;
808:
809: if(node==NULL) {
810: strncpy(buf,"(null)",buflen);
811: return(buf);
812: }
813:
814: switch(node->status) {
815: case NODE_WFC:
816: strcpy(str,"Waiting for call");
817: break;
818: case NODE_OFFLINE:
819: strcpy(str,"Offline");
820: break;
821: case NODE_NETTING:
822: strcpy(str,"Networking");
823: break;
824: case NODE_LOGON:
825: strcpy(str,"At logon prompt");
826: break;
827: case NODE_EVENT_WAITING:
828: strcpy(str,"Waiting for all nodes to become inactive");
829: break;
830: case NODE_EVENT_LIMBO:
831: sprintf(str,"Waiting for node %d to finish external event"
832: ,node->aux);
833: break;
834: case NODE_EVENT_RUNNING:
835: strcpy(str,"Running external event");
836: break;
837: case NODE_NEWUSER:
838: strcpy(str,"New user applying for access ");
839: if(!node->connection)
840: strcat(str,"Locally");
841: else if(node->connection==0xffff) {
842: strcat(str,"via telnet");
843: } else
844: sprintf(str+strlen(str),"at %ubps",node->connection);
845: break;
846: case NODE_QUIET:
847: case NODE_INUSE:
848: username(cfg,node->useron,str);
849: strcat(str," ");
850: switch(node->action) {
851: case NODE_MAIN:
852: strcat(str,"at main menu");
853: break;
854: case NODE_RMSG:
855: strcat(str,"reading messages");
856: break;
857: case NODE_RMAL:
858: strcat(str,"reading mail");
859: break;
860: case NODE_RSML:
861: strcat(str,"reading sent mail");
862: break;
863: case NODE_RTXT:
864: strcat(str,"reading text files");
865: break;
866: case NODE_PMSG:
867: strcat(str,"posting message");
868: break;
869: case NODE_SMAL:
870: strcat(str,"sending mail");
871: break;
872: case NODE_AMSG:
873: strcat(str,"posting auto-message");
874: break;
875: case NODE_XTRN:
876: if(!node->aux)
877: strcat(str,"at external program menu");
878: else if(node->aux<=cfg->total_xtrns)
879: sprintf(str+strlen(str),"running %s"
880: ,cfg->xtrn[node->aux-1]->name);
881: else
882: sprintf(str+strlen(str),"running external program #%d"
883: ,node->aux);
884: break;
885: case NODE_DFLT:
886: strcat(str,"changing defaults");
887: break;
888: case NODE_XFER:
889: strcat(str,"at transfer menu");
890: break;
891: case NODE_RFSD:
892: sprintf(str+strlen(str),"retrieving from device #%d",node->aux);
893: break;
894: case NODE_DLNG:
895: strcat(str,"downloading");
896: break;
897: case NODE_ULNG:
898: strcat(str,"uploading");
899: break;
900: case NODE_BXFR:
901: strcat(str,"transferring bidirectional");
902: break;
903: case NODE_LFIL:
904: strcat(str,"listing files");
905: break;
906: case NODE_LOGN:
907: strcat(str,"logging on");
908: break;
909: case NODE_LCHT:
910: strcat(str,"in local chat with sysop");
911: break;
912: case NODE_MCHT:
913: if(node->aux) {
914: sprintf(str+strlen(str),"in multinode chat channel %d"
915: ,node->aux&0xff);
916: if(node->aux&0x1f00) { /* password */
917: strcat(str,"* ");
918: unpackchatpass(str+strlen(str),node);
919: }
920: }
921: else
922: strcat(str,"in multinode global chat channel");
923: break;
924: case NODE_PAGE:
925: sprintf(str+strlen(str)
926: ,"paging node %u for private chat",node->aux);
927: break;
928: case NODE_PCHT:
929: if(!node->aux)
930: strcat(str,"in local chat with sysop");
931: else
932: sprintf(str+strlen(str)
933: ,"in private chat with node %u"
934: ,node->aux);
935: break;
936: case NODE_GCHT:
937: strcat(str,"chatting with The Guru");
938: break;
939: case NODE_CHAT:
940: strcat(str,"in chat section");
941: break;
942: case NODE_TQWK:
943: strcat(str,"transferring QWK packet");
944: break;
945: case NODE_SYSP:
946: strcat(str,"performing sysop activities");
947: break;
948: default:
949: sprintf(str+strlen(str),"%d",node->action);
950: break;
951: }
952: if(!node->connection)
953: strcat(str," locally");
954: if(node->connection==0xffff) {
955: strcat(str," via telnet");
956: } else
957: sprintf(str+strlen(str)," at %ubps",node->connection);
958: if(node->action==NODE_DLNG) {
959: if((node->aux/60)>=12) {
960: if(node->aux/60==12)
961: hour=12;
962: else
963: hour=(node->aux/60)-12;
964: mer="pm";
965: } else {
966: if((node->aux/60)==0) /* 12 midnite */
967: hour=12;
968: else hour=node->aux/60;
969: mer="am";
970: }
971: sprintf(str+strlen(str), " ETA %02d:%02d %s"
972: ,hour,node->aux-((node->aux/60)*60),mer);
973: }
974: break;
975: }
976: if(node->misc&(NODE_LOCK|NODE_POFF|NODE_AOFF|NODE_MSGW|NODE_NMSG)) {
977: strcat(str," (");
978: if(node->misc&NODE_AOFF)
979: strcat(str,"A");
980: if(node->misc&NODE_LOCK)
981: strcat(str,"L");
982: if(node->misc&(NODE_MSGW|NODE_NMSG))
983: strcat(str,"M");
984: if(node->misc&NODE_POFF)
985: strcat(str,"P");
986: strcat(str,")");
987: }
988: if(((node->misc
989: &(NODE_ANON|NODE_UDAT|NODE_INTR|NODE_RRUN|NODE_EVENT|NODE_DOWN))
990: || node->status==NODE_QUIET)) {
991: strcat(str," [");
992: if(node->misc&NODE_ANON)
993: strcat(str,"A");
994: if(node->misc&NODE_INTR)
995: strcat(str,"I");
996: if(node->misc&NODE_RRUN)
997: strcat(str,"R");
998: if(node->misc&NODE_UDAT)
999: strcat(str,"U");
1000: if(node->status==NODE_QUIET)
1001: strcat(str,"Q");
1002: if(node->misc&NODE_EVENT)
1003: strcat(str,"E");
1004: if(node->misc&NODE_DOWN)
1005: strcat(str,"D");
1006: if(node->misc&NODE_LCHAT)
1007: strcat(str,"C");
1008: strcat(str,"]");
1009: }
1010: if(node->errors)
1011: sprintf(str+strlen(str)
1012: ," %d error%c",node->errors, node->errors>1 ? 's' : '\0' );
1013:
1014: strncpy(buf,str,buflen);
1015:
1016: return(buf);
1017: }
1018:
1019: /****************************************************************************/
1020: /* Displays the information for node number 'number' contained in 'node' */
1021: /****************************************************************************/
1022: void DLLCALL printnodedat(scfg_t* cfg, uint number, node_t* node)
1023: {
1024: char status[128];
1025:
1026: printf("Node %2d: %s\n",number,nodestatus(cfg,node,status,sizeof(status)));
1027: }
1028:
1029: /****************************************************************************/
1030: uint DLLCALL userdatdupe(scfg_t* cfg, uint usernumber, uint offset, uint datlen
1031: ,char *dat, BOOL del)
1032: {
1033: char str[MAX_PATH+1];
1034: uint i;
1035: int file;
1036: long l,length;
1037:
1038: if(!VALID_CFG(cfg) || dat==NULL)
1039: return(0);
1040:
1041: truncsp(dat);
1042: sprintf(str,"%suser/user.dat", cfg->data_dir);
1043: if((file=nopen(str,O_RDONLY|O_DENYNONE))==-1)
1044: return(0);
1045: length=filelength(file);
1046: for(l=0;l<length;l+=U_LEN) {
1047: if(usernumber && l/U_LEN==(long)usernumber-1)
1048: continue;
1049: lseek(file,l+offset,SEEK_SET);
1050: i=0;
1051: while(i<LOOP_NODEDAB && lock(file,l,U_LEN)==-1) {
1052: if(i)
1053: mswait(100);
1054: i++;
1055: }
1056:
1057: if(i>=LOOP_NODEDAB) {
1058: close(file);
1059: return(0);
1060: }
1061:
1062: read(file,str,datlen);
1063: for(i=0;i<datlen;i++)
1064: if(str[i]==ETX) break;
1065: str[i]=0;
1066: truncsp(str);
1067: if(!stricmp(str,dat)) {
1068: if(!del) { /* Don't include deleted users in search */
1069: lseek(file,l+U_MISC,SEEK_SET);
1070: read(file,str,8);
1071: getrec(str,0,8,str);
1072: if(ahtoul(str)&(DELETED|INACTIVE)) {
1073: unlock(file,l,U_LEN);
1074: continue;
1075: }
1076: }
1077: unlock(file,l,U_LEN);
1078: close(file);
1079: return((l/U_LEN)+1);
1080: } else
1081: unlock(file,l,U_LEN);
1082: }
1083: close(file);
1084: return(0);
1085: }
1086:
1087: /****************************************************************************/
1088: /* Creates a short message for 'usernumber' that contains 'strin' */
1089: /****************************************************************************/
1090: int DLLCALL putsmsg(scfg_t* cfg, int usernumber, char *strin)
1091: {
1092: char str[256];
1093: int file,i;
1094: node_t node;
1095:
1096: if(!VALID_CFG(cfg) || usernumber<1 || strin==NULL)
1097: return(-1);
1098:
1099: if(*strin==0)
1100: return(0);
1101:
1102: sprintf(str,"%smsgs/%4.4u.msg",cfg->data_dir,usernumber);
1103: if((file=nopen(str,O_WRONLY|O_CREAT|O_APPEND))==-1) {
1104: return(errno);
1105: }
1106: i=strlen(strin);
1107: if(write(file,strin,i)!=i) {
1108: close(file);
1109: return(errno);
1110: }
1111: close(file);
1112: for(i=1;i<=cfg->sys_nodes;i++) { /* flag node if user on that msg waiting */
1113: getnodedat(cfg,i,&node,NULL);
1114: if(node.useron==usernumber
1115: && (node.status==NODE_INUSE || node.status==NODE_QUIET)
1116: && !(node.misc&NODE_MSGW)) {
1117: getnodedat(cfg,i,&node,&file);
1118: node.misc|=NODE_MSGW;
1119: putnodedat(cfg,i,&node,file);
1120: }
1121: }
1122: return(0);
1123: }
1124:
1125: /****************************************************************************/
1126: /* Returns any short messages waiting for user number, buffer must be freed */
1127: /****************************************************************************/
1128: char* DLLCALL getsmsg(scfg_t* cfg, int usernumber)
1129: {
1130: char str[MAX_PATH+1], *buf;
1131: int i;
1132: int file;
1133: long length;
1134: node_t node;
1135:
1136: if(!VALID_CFG(cfg) || usernumber<1)
1137: return(NULL);
1138:
1139: sprintf(str,"%smsgs/%4.4u.msg",cfg->data_dir,usernumber);
1140: if(flength(str)<1L)
1141: return(NULL);
1142: if((file=nopen(str,O_RDWR))==-1)
1143: return(NULL);
1144: length=filelength(file);
1145: if((buf=(char *)malloc(length+1))==NULL) {
1146: close(file);
1147: return(NULL);
1148: }
1149: if(read(file,buf,length)!=length) {
1150: close(file);
1151: free(buf);
1152: return(NULL);
1153: }
1154: chsize(file,0L);
1155: close(file);
1156: buf[length]=0;
1157:
1158: for(i=1;i<=cfg->sys_nodes;i++) { /* clear msg waiting flag */
1159: getnodedat(cfg,i,&node,NULL);
1160: if(node.useron==usernumber
1161: && (node.status==NODE_INUSE || node.status==NODE_QUIET)
1162: && node.misc&NODE_MSGW) {
1163: getnodedat(cfg,i,&node,&file);
1164: node.misc&=~NODE_MSGW;
1165: putnodedat(cfg,i,&node,file);
1166: }
1167: }
1168:
1169: return(buf); /* caller must free */
1170: }
1171:
1172: char* DLLCALL getnmsg(scfg_t* cfg, int node_num)
1173: {
1174: char str[MAX_PATH+1];
1175: char* buf;
1176: int file;
1177: long length;
1178: node_t node;
1179:
1180: if(!VALID_CFG(cfg) || node_num<1)
1181: return(NULL);
1182:
1183: getnodedat(cfg,node_num,&node,&file);
1184: node.misc&=~NODE_NMSG; /* clear the NMSG flag */
1185: putnodedat(cfg,node_num,&node,file);
1186:
1187: sprintf(str,"%smsgs/n%3.3u.msg",cfg->data_dir,node_num);
1188: if(flength(str)<1L)
1189: return(NULL);
1190: if((file=nopen(str,O_RDWR))==-1)
1191: return(NULL);
1192: length=filelength(file);
1193: if(!length) {
1194: close(file);
1195: return(NULL);
1196: }
1197: if((buf=(char *)malloc(length+1))==NULL) {
1198: close(file);
1199: return(NULL);
1200: }
1201: if(read(file,buf,length)!=length) {
1202: close(file);
1203: free(buf);
1204: return(NULL);
1205: }
1206: chsize(file,0L);
1207: close(file);
1208: buf[length]=0;
1209:
1210: return(buf); /* caller must free */
1211: }
1212:
1213: /****************************************************************************/
1214: /* Creates a short message for node 'num' that contains 'strin' */
1215: /****************************************************************************/
1216: int DLLCALL putnmsg(scfg_t* cfg, int num, char *strin)
1217: {
1218: char str[256];
1219: int file,i;
1220: node_t node;
1221:
1222: if(!VALID_CFG(cfg) || num<1 || strin==NULL)
1223: return(-1);
1224:
1225: if(*strin==0)
1226: return(0);
1227:
1228: sprintf(str,"%smsgs/n%3.3u.msg",cfg->data_dir,num);
1229: if((file=nopen(str,O_WRONLY|O_CREAT))==-1)
1230: return(errno);
1231: lseek(file,0L,SEEK_END); /* Instead of opening with O_APPEND */
1232: i=strlen(strin);
1233: if(write(file,strin,i)!=i) {
1234: close(file);
1235: return(errno);
1236: }
1237: close(file);
1238: getnodedat(cfg,num,&node,NULL);
1239: if((node.status==NODE_INUSE || node.status==NODE_QUIET)
1240: && !(node.misc&NODE_NMSG)) {
1241: getnodedat(cfg,num,&node,&file);
1242: node.misc|=NODE_NMSG;
1243: putnodedat(cfg,num,&node,file);
1244: }
1245:
1246: return(0);
1247: }
1248:
1249: static int getdirnum(scfg_t* cfg, char* code)
1250: {
1251: size_t i;
1252:
1253: for(i=0;i<cfg->total_dirs;i++)
1254: if(stricmp(cfg->dir[i]->code,code)==0)
1255: return(i);
1256: return(-1);
1257: }
1258:
1259: static int getlibnum(scfg_t* cfg, char* code)
1260: {
1261: size_t i;
1262:
1263: for(i=0;i<cfg->total_dirs;i++)
1264: if(stricmp(cfg->dir[i]->code,code)==0)
1265: return(cfg->dir[i]->lib);
1266: return(-1);
1267: }
1268:
1269: static int getsubnum(scfg_t* cfg, char* code)
1270: {
1271: size_t i;
1272:
1273: for(i=0;i<cfg->total_subs;i++)
1274: if(stricmp(cfg->sub[i]->code,code)==0)
1275: return(i);
1276: return(-1);
1277: }
1278:
1279: static int getgrpnum(scfg_t* cfg, char* code)
1280: {
1281: size_t i;
1282:
1283: for(i=0;i<cfg->total_subs;i++)
1284: if(stricmp(cfg->sub[i]->code,code)==0)
1285: return(cfg->sub[i]->grp);
1286: return(-1);
1287: }
1288:
1289: static BOOL ar_exp(scfg_t* cfg, uchar **ptrptr, user_t* user)
1290: {
1291: BOOL result,not,or,equal;
1292: uint i,n,artype=AR_LEVEL,age;
1293: ulong l;
1294: time_t now;
1295: struct tm tm;
1296:
1297: result = TRUE;
1298:
1299: for(;(**ptrptr);(*ptrptr)++) {
1300:
1301: if((**ptrptr)==AR_ENDNEST)
1302: break;
1303:
1304: not=or=equal = FALSE;
1305:
1306: if((**ptrptr)==AR_OR) {
1307: or=1;
1308: (*ptrptr)++;
1309: }
1310:
1311: if((**ptrptr)==AR_NOT) {
1312: not=1;
1313: (*ptrptr)++;
1314: }
1315:
1316: if((**ptrptr)==AR_EQUAL) {
1317: equal=1;
1318: (*ptrptr)++;
1319: }
1320:
1321: if((result && or) || (!result && !or))
1322: break;
1323:
1324: if((**ptrptr)==AR_BEGNEST) {
1325: (*ptrptr)++;
1326: if(ar_exp(cfg,ptrptr,user))
1327: result=!not;
1328: else
1329: result=not;
1330: while((**ptrptr)!=AR_ENDNEST && (**ptrptr)) /* in case of early exit */
1331: (*ptrptr)++;
1332: if(!(**ptrptr))
1333: break;
1334: continue;
1335: }
1336:
1337: artype=(**ptrptr);
1338: switch(artype) {
1339: case AR_ANSI: /* No arguments */
1340: case AR_RIP:
1341: case AR_WIP:
1342: case AR_LOCAL:
1343: case AR_EXPERT:
1344: case AR_SYSOP:
1345: case AR_GUEST:
1346: case AR_QNODE:
1347: case AR_QUIET:
1348: case AR_OS2:
1349: case AR_DOS:
1350: break;
1351: default:
1352: (*ptrptr)++;
1353: break;
1354: }
1355:
1356: n=(**ptrptr);
1357: i=(*(short *)*ptrptr);
1358: switch(artype) {
1359: case AR_LEVEL:
1360: if(user==NULL
1361: || (equal && user->level!=n)
1362: || (!equal && user->level<n))
1363: result=not;
1364: else
1365: result=!not;
1366: break;
1367: case AR_AGE:
1368: if(user==NULL)
1369: result=not;
1370: else {
1371: age=getage(cfg,user->birth);
1372: if((equal && age!=n) || (!equal && age<n))
1373: result=not;
1374: else
1375: result=!not;
1376: }
1377: break;
1378: case AR_BPS:
1379: result=!not;
1380: (*ptrptr)++;
1381: break;
1382: case AR_ANSI:
1383: if(user==NULL || !(user->misc&ANSI))
1384: result=not;
1385: else result=!not;
1386: break;
1387: case AR_RIP:
1388: if(user==NULL || !(user->misc&RIP))
1389: result=not;
1390: else result=!not;
1391: break;
1392: case AR_WIP:
1393: if(user==NULL || !(user->misc&WIP))
1394: result=not;
1395: else result=!not;
1396: break;
1397: case AR_OS2:
1398: #ifndef __OS2__
1399: result=not;
1400: #else
1401: result=!not;
1402: #endif
1403: break;
1404: case AR_DOS:
1405: result=not;
1406: break;
1407: case AR_WIN32:
1408: #ifndef _WIN32
1409: result=not;
1410: #else
1411: result=!not;
1412: #endif
1413: break;
1414: case AR_UNIX:
1415: #ifndef __unix__
1416: result=not;
1417: #else
1418: result=!not;
1419: #endif
1420: break;
1421: case AR_LINUX:
1422: #ifndef __linux__
1423: result=not;
1424: #else
1425: result=!not;
1426: #endif
1427: break;
1428: case AR_ACTIVE:
1429: if(user==NULL || user->misc&(DELETED|INACTIVE))
1430: result=not;
1431: else result=!not;
1432: break;
1433: case AR_INACTIVE:
1434: if(user==NULL || !(user->misc&INACTIVE))
1435: result=not;
1436: else result=!not;
1437: break;
1438: case AR_DELETED:
1439: if(user==NULL || !(user->misc&DELETED))
1440: result=not;
1441: else result=!not;
1442: break;
1443: case AR_EXPERT:
1444: if(user==NULL || !(user->misc&EXPERT))
1445: result=not;
1446: else result=!not;
1447: break;
1448: case AR_SYSOP:
1449: if(user==NULL || user->level<SYSOP_LEVEL)
1450: result=not;
1451: else result=!not;
1452: break;
1453: case AR_GUEST:
1454: if(user==NULL || !(user->rest&FLAG('G')))
1455: result=not;
1456: else result=!not;
1457: break;
1458: case AR_QNODE:
1459: if(user==NULL || !(user->rest&FLAG('Q')))
1460: result=not;
1461: else result=!not;
1462: break;
1463: case AR_QUIET:
1464: result=not;
1465: break;
1466: case AR_LOCAL:
1467: result=not;
1468: break;
1469: case AR_DAY:
1470: now=time(NULL);
1471: localtime_r(&now,&tm);
1472: if((equal && tm.tm_wday!=(int)n)
1473: || (!equal && tm.tm_wday<(int)n))
1474: result=not;
1475: else
1476: result=!not;
1477: break;
1478: case AR_CREDIT:
1479: l=(ulong)i*1024UL;
1480: if(user==NULL
1481: || (equal && user->cdt+user->freecdt!=l)
1482: || (!equal && user->cdt+user->freecdt<l))
1483: result=not;
1484: else
1485: result=!not;
1486: (*ptrptr)++;
1487: break;
1488: case AR_NODE:
1489: if((equal && cfg->node_num!=n) || (!equal && cfg->node_num<n))
1490: result=not;
1491: else
1492: result=!not;
1493: break;
1494: case AR_USER:
1495: if(user==NULL
1496: || (equal && user->number!=i)
1497: || (!equal && user->number<i))
1498: result=not;
1499: else
1500: result=!not;
1501: (*ptrptr)++;
1502: break;
1503: case AR_GROUP:
1504: if(user==NULL)
1505: result=not;
1506: else {
1507: l=getgrpnum(cfg,user->cursub);
1508: if((equal && l!=i) || (!equal && l<i))
1509: result=not;
1510: else
1511: result=!not;
1512: }
1513: (*ptrptr)++;
1514: break;
1515: case AR_SUB:
1516: if(user==NULL)
1517: result=not;
1518: else {
1519: l=getsubnum(cfg,user->cursub);
1520: if((equal && l!=i) || (!equal && l<i))
1521: result=not;
1522: else
1523: result=!not;
1524: }
1525: (*ptrptr)++;
1526: break;
1527: case AR_SUBCODE:
1528: if(user!=NULL && stricmp(user->cursub,(char *)*ptrptr)==0)
1529: result=!not;
1530: else
1531: result=not;
1532: result=not;
1533: while(*(*ptrptr))
1534: (*ptrptr)++;
1535: break;
1536: case AR_LIB:
1537: if(user==NULL)
1538: result=not;
1539: else {
1540: l=getlibnum(cfg,user->curdir);
1541: if((equal && l!=i) || (!equal && l<i))
1542: result=not;
1543: else
1544: result=!not;
1545: }
1546: (*ptrptr)++;
1547: break;
1548: case AR_DIR:
1549: if(user==NULL)
1550: result=not;
1551: else {
1552: l=getdirnum(cfg,user->curdir);
1553: if((equal && l!=i) || (!equal && l<i))
1554: result=not;
1555: else
1556: result=!not;
1557: }
1558: (*ptrptr)++;
1559: break;
1560: case AR_DIRCODE:
1561: if(user!=NULL && stricmp(user->curdir,(char *)*ptrptr)==0)
1562: result=!not;
1563: else
1564: result=not;
1565: while(*(*ptrptr))
1566: (*ptrptr)++;
1567: break;
1568: case AR_EXPIRE:
1569: now=time(NULL);
1570: if(user==NULL
1571: || user->expire==0
1572: || now+((long)i*24L*60L*60L)>user->expire)
1573: result=not;
1574: else
1575: result=!not;
1576: (*ptrptr)++;
1577: break;
1578: case AR_RANDOM:
1579: n=xp_random(i+1);
1580: if((equal && n!=i) || (!equal && n<i))
1581: result=not;
1582: else
1583: result=!not;
1584: (*ptrptr)++;
1585: break;
1586: case AR_LASTON:
1587: now=time(NULL);
1588: if(user==NULL || (now-user->laston)/(24L*60L*60L)<(long)i)
1589: result=not;
1590: else
1591: result=!not;
1592: (*ptrptr)++;
1593: break;
1594: case AR_LOGONS:
1595: if(user==NULL
1596: || (equal && user->logons!=i)
1597: || (!equal && user->logons<i))
1598: result=not;
1599: else
1600: result=!not;
1601: (*ptrptr)++;
1602: break;
1603: case AR_MAIN_CMDS:
1604: result=not;
1605: (*ptrptr)++;
1606: break;
1607: case AR_FILE_CMDS:
1608: result=not;
1609: (*ptrptr)++;
1610: break;
1611: case AR_TLEFT:
1612: result=not;
1613: break;
1614: case AR_TUSED:
1615: result=not;
1616: break;
1617: case AR_TIME:
1618: now=time(NULL);
1619: localtime_r(&now,&tm);
1620: if((tm.tm_hour*60)+tm.tm_min<(int)i)
1621: result=not;
1622: else
1623: result=!not;
1624: (*ptrptr)++;
1625: break;
1626: case AR_PCR:
1627: if(user==NULL)
1628: result=not;
1629: else if(user->logons>user->posts
1630: && (!user->posts || 100/((float)user->logons/user->posts)<(long)n))
1631: result=not;
1632: else
1633: result=!not;
1634: break;
1635: case AR_UDR: /* up/download byte ratio */
1636: if(user==NULL)
1637: result=not;
1638: else {
1639: l=user->dlb;
1640: if(!l) l=1;
1641: if(user->dlb>user->ulb
1642: && (!user->ulb || 100/((float)l/user->ulb)<n))
1643: result=not;
1644: else
1645: result=!not;
1646: }
1647: break;
1648: case AR_UDFR: /* up/download file ratio */
1649: if(user==NULL)
1650: result=not;
1651: else {
1652: i=user->dls;
1653: if(!i) i=1;
1654: if(user->dls>user->uls
1655: && (!user->uls || 100/((float)i/user->uls)<n))
1656: result=not;
1657: else
1658: result=!not;
1659: }
1660: break;
1661: case AR_FLAG1:
1662: if(user==NULL
1663: || (!equal && !(user->flags1&FLAG(n)))
1664: || (equal && user->flags1!=FLAG(n)))
1665: result=not;
1666: else
1667: result=!not;
1668: break;
1669: case AR_FLAG2:
1670: if(user==NULL
1671: || (!equal && !(user->flags2&FLAG(n)))
1672: || (equal && user->flags2!=FLAG(n)))
1673: result=not;
1674: else
1675: result=!not;
1676: break;
1677: case AR_FLAG3:
1678: if(user==NULL
1679: || (!equal && !(user->flags3&FLAG(n)))
1680: || (equal && user->flags3!=FLAG(n)))
1681: result=not;
1682: else
1683: result=!not;
1684: break;
1685: case AR_FLAG4:
1686: if(user==NULL
1687: || (!equal && !(user->flags4&FLAG(n)))
1688: || (equal && user->flags4!=FLAG(n)))
1689: result=not;
1690: else
1691: result=!not;
1692: break;
1693: case AR_REST:
1694: if(user==NULL
1695: || (!equal && !(user->rest&FLAG(n)))
1696: || (equal && user->rest!=FLAG(n)))
1697: result=not;
1698: else
1699: result=!not;
1700: break;
1701: case AR_EXEMPT:
1702: if(user==NULL
1703: || (!equal && !(user->exempt&FLAG(n)))
1704: || (equal && user->exempt!=FLAG(n)))
1705: result=not;
1706: else
1707: result=!not;
1708: break;
1709: case AR_SEX:
1710: if(user==NULL || user->sex!=n)
1711: result=not;
1712: else
1713: result=!not;
1714: break;
1715: case AR_SHELL:
1716: if(user==NULL
1717: || user->shell>=cfg->total_shells
1718: || stricmp(cfg->shell[user->shell]->code,(char*)*ptrptr))
1719: result=not;
1720: else
1721: result=!not;
1722: while(*(*ptrptr))
1723: (*ptrptr)++;
1724: break;
1725: case AR_PROT:
1726: if(user==NULL
1727: || stricmp(user->modem,(char*)*ptrptr)) /* should this be changed to client.prot? */
1728: result=not;
1729: else
1730: result=!not;
1731: while(*(*ptrptr))
1732: (*ptrptr)++;
1733: break;
1734: }
1735: }
1736: return(result);
1737: }
1738:
1739: BOOL DLLCALL chk_ar(scfg_t* cfg, uchar *ar, user_t* user)
1740: {
1741: uchar *p;
1742:
1743: if(ar==NULL)
1744: return(TRUE);
1745: if(!VALID_CFG(cfg))
1746: return(FALSE);
1747: p=ar;
1748: return(ar_exp(cfg,&p,user));
1749: }
1750:
1751: /****************************************************************************/
1752: /* Fills 'str' with record for usernumber starting at start for length bytes*/
1753: /* Called from function ??? */
1754: /****************************************************************************/
1755: int DLLCALL getuserrec(scfg_t* cfg, int usernumber,int start, int length, char *str)
1756: {
1757: char path[256];
1758: int i,c,file;
1759:
1760: if(!VALID_CFG(cfg) || usernumber<1 || str==NULL)
1761: return(-1);
1762: sprintf(path,"%suser/user.dat",cfg->data_dir);
1763: if((file=nopen(path,O_RDONLY|O_DENYNONE))==-1)
1764: return(errno);
1765: if(usernumber<1
1766: || filelength(file)<(long)((long)(usernumber-1L)*U_LEN)+(long)start) {
1767: close(file);
1768: return(-2);
1769: }
1770: lseek(file,(long)((long)(usernumber-1)*U_LEN)+start,SEEK_SET);
1771:
1772: if(length==0) /* auto-length */
1773: length=user_rec_len(start);
1774:
1775: i=0;
1776: while(i<LOOP_NODEDAB
1777: && lock(file,(long)((long)(usernumber-1)*U_LEN)+start,length)==-1) {
1778: if(i)
1779: mswait(100);
1780: i++;
1781: }
1782:
1783: if(i>=LOOP_NODEDAB) {
1784: close(file);
1785: return(-3);
1786: }
1787:
1788: if(read(file,str,length)!=length) {
1789: unlock(file,(long)((long)(usernumber-1)*U_LEN)+start,length);
1790: close(file);
1791: return(-4);
1792: }
1793:
1794: unlock(file,(long)((long)(usernumber-1)*U_LEN)+start,length);
1795: close(file);
1796: for(c=0;c<length;c++)
1797: if(str[c]==ETX || str[c]==CR) break;
1798: str[c]=0;
1799:
1800: return(0);
1801: }
1802:
1803: /****************************************************************************/
1804: /* Places into user.dat at the offset for usernumber+start for length bytes */
1805: /* Called from various locations */
1806: /****************************************************************************/
1807: int DLLCALL putuserrec(scfg_t* cfg, int usernumber,int start, uint length, char *str)
1808: {
1809: char str2[256];
1810: int file;
1811: uint c,i;
1812: node_t node;
1813:
1814: if(!VALID_CFG(cfg) || usernumber<1 || str==NULL)
1815: return(-1);
1816:
1817: sprintf(str2,"%suser/user.dat",cfg->data_dir);
1818: if((file=nopen(str2,O_RDWR|O_DENYNONE))==-1)
1819: return(errno);
1820:
1821: if(filelength(file)<((long)usernumber-1)*U_LEN) {
1822: close(file);
1823: return(-4);
1824: }
1825:
1826: if(length==0) /* auto-length */
1827: length=user_rec_len(start);
1828:
1829: strcpy(str2,str);
1830: if(strlen(str2)<length) {
1831: for(c=strlen(str2);c<length;c++)
1832: str2[c]=ETX;
1833: str2[c]=0;
1834: }
1835: lseek(file,(long)((long)((long)((long)usernumber-1)*U_LEN)+start),SEEK_SET);
1836:
1837: i=0;
1838: while(i<LOOP_NODEDAB
1839: && lock(file,(long)((long)(usernumber-1)*U_LEN)+start,length)==-1) {
1840: if(i)
1841: mswait(100);
1842: i++;
1843: }
1844:
1845: if(i>=LOOP_NODEDAB)
1846: return(-3);
1847:
1848: write(file,str2,length);
1849: unlock(file,(long)((long)(usernumber-1)*U_LEN)+start,length);
1850: close(file);
1851: for(i=1;i<=cfg->sys_nodes;i++) { /* instant user data update */
1852: if(i==cfg->node_num)
1853: continue;
1854: getnodedat(cfg, i,&node,NULL);
1855: if(node.useron==usernumber && (node.status==NODE_INUSE
1856: || node.status==NODE_QUIET)) {
1857: getnodedat(cfg, i,&node,&file);
1858: node.misc|=NODE_UDAT;
1859: putnodedat(cfg, i,&node,file);
1860: break;
1861: }
1862: }
1863:
1864: return(0);
1865: }
1866:
1867: /****************************************************************************/
1868: /* Updates user 'usernumber's record (numeric string) by adding 'adj' to it */
1869: /* returns the new value. */
1870: /****************************************************************************/
1871: ulong DLLCALL adjustuserrec(scfg_t* cfg, int usernumber, int start, int length, long adj)
1872: {
1873: char str[256],path[256];
1874: char tmp[32];
1875: int i,c,file;
1876: long val;
1877: node_t node;
1878:
1879: if(!VALID_CFG(cfg) || usernumber<1)
1880: return(0);
1881:
1882: sprintf(path,"%suser/user.dat",cfg->data_dir);
1883: if((file=nopen(path,O_RDWR|O_DENYNONE))==-1)
1884: return(0);
1885:
1886: if(filelength(file)<((long)usernumber-1)*U_LEN) {
1887: close(file);
1888: return(0);
1889: }
1890:
1891: lseek(file,(long)((long)(usernumber-1)*U_LEN)+start,SEEK_SET);
1892:
1893: if(length==0) /* auto-length */
1894: length=user_rec_len(start);
1895:
1896: i=0;
1897: while(i<LOOP_NODEDAB
1898: && lock(file,(long)((long)(usernumber-1)*U_LEN)+start,length)==-1) {
1899: if(i)
1900: mswait(100);
1901: i++;
1902: }
1903:
1904: if(i>=LOOP_NODEDAB) {
1905: close(file);
1906: return(0);
1907: }
1908:
1909: if(read(file,str,length)!=length) {
1910: unlock(file,(long)((long)(usernumber-1)*U_LEN)+start,length);
1911: close(file);
1912: return(0);
1913: }
1914: for(c=0;c<length;c++)
1915: if(str[c]==ETX || str[c]==CR) break;
1916: str[c]=0;
1917: val=atol(str);
1918: if(adj<0L && val<-adj) /* don't go negative */
1919: val=0;
1920: else val+=adj;
1921: lseek(file,(long)((long)(usernumber-1)*U_LEN)+start,SEEK_SET);
1922: putrec(str,0,length,ultoa(val,tmp,10));
1923: if(write(file,str,length)!=length) {
1924: unlock(file,(long)((long)(usernumber-1)*U_LEN)+start,length);
1925: close(file);
1926: return(val);
1927: }
1928: unlock(file,(long)((long)(usernumber-1)*U_LEN)+start,length);
1929: close(file);
1930: for(i=1;i<=cfg->sys_nodes;i++) { /* instant user data update */
1931: if(i==cfg->node_num)
1932: continue;
1933: getnodedat(cfg, i,&node,NULL);
1934: if(node.useron==usernumber && (node.status==NODE_INUSE
1935: || node.status==NODE_QUIET)) {
1936: getnodedat(cfg, i,&node,&file);
1937: node.misc|=NODE_UDAT;
1938: putnodedat(cfg, i,&node,file);
1939: break;
1940: }
1941: }
1942: return(val);
1943: }
1944:
1945: /****************************************************************************/
1946: /* Subtract credits from the current user online, accounting for the new */
1947: /* "free credits" field. */
1948: /****************************************************************************/
1949: void DLLCALL subtract_cdt(scfg_t* cfg, user_t* user, long amt)
1950: {
1951: char tmp[64];
1952: long mod;
1953:
1954: if(!amt || user==NULL)
1955: return;
1956: if(user->freecdt) {
1957: if((ulong)amt>user->freecdt) { /* subtract both credits and */
1958: mod=amt-user->freecdt; /* free credits */
1959: putuserrec(cfg, user->number,U_FREECDT,10,"0");
1960: user->freecdt=0;
1961: user->cdt=adjustuserrec(cfg, user->number,U_CDT,10,-mod);
1962: } else { /* subtract just free credits */
1963: user->freecdt-=amt;
1964: putuserrec(cfg, user->number,U_FREECDT,10
1965: ,ultoa(user->freecdt,tmp,10));
1966: }
1967: }
1968: else /* no free credits */
1969: user->cdt=adjustuserrec(cfg, user->number,U_CDT,10,-amt);
1970: }
1971:
1972: BOOL DLLCALL user_posted_msg(scfg_t* cfg, user_t* user, int count)
1973: {
1974: if(user==NULL)
1975: return(FALSE);
1976:
1977: user->posts =(ushort)adjustuserrec(cfg, user->number, U_POSTS, 5, count);
1978: user->ptoday=(ushort)adjustuserrec(cfg, user->number, U_PTODAY, 5, count);
1979:
1980: return(TRUE);
1981: }
1982:
1983: BOOL DLLCALL user_sent_email(scfg_t* cfg, user_t* user, int count, BOOL feedback)
1984: {
1985: if(user==NULL)
1986: return(FALSE);
1987:
1988: if(feedback)
1989: user->fbacks=(ushort)adjustuserrec(cfg, user->number, U_FBACKS, 5, count);
1990: else
1991: user->emails=(ushort)adjustuserrec(cfg, user->number, U_EMAILS, 5, count);
1992: user->etoday=(ushort)adjustuserrec(cfg, user->number, U_ETODAY, 5, count);
1993:
1994: return(TRUE);
1995: }
1996:
1997: BOOL DLLCALL user_downloaded(scfg_t* cfg, user_t* user, int files, long bytes)
1998: {
1999: if(user==NULL)
2000: return(FALSE);
2001:
2002: user->dls=(ushort)adjustuserrec(cfg, user->number, U_DLS, 5, files);
2003: user->dlb=adjustuserrec(cfg, user->number, U_DLB, 10, bytes);
2004:
2005: return(TRUE);
2006: }
2007:
2008: BOOL DLLCALL user_uploaded(scfg_t* cfg, user_t* user, int files, long bytes)
2009: {
2010: if(user==NULL)
2011: return(FALSE);
2012:
2013: user->uls=(ushort)adjustuserrec(cfg, user->number, U_ULS, 5, files);
2014: user->ulb=adjustuserrec(cfg, user->number, U_ULB, 10, bytes);
2015:
2016: return(TRUE);
2017: }
2018:
2019: BOOL DLLCALL user_adjust_credits(scfg_t* cfg, user_t* user, long amount)
2020: {
2021: if(user==NULL)
2022: return(FALSE);
2023:
2024: if(amount<0) /* subtract */
2025: subtract_cdt(cfg, user, -amount);
2026: else /* add */
2027: user->cdt=adjustuserrec(cfg, user->number, U_CDT, 10, amount);
2028:
2029: return(TRUE);
2030: }
2031:
2032: BOOL DLLCALL user_adjust_minutes(scfg_t* cfg, user_t* user, long amount)
2033: {
2034: if(user==NULL)
2035: return(FALSE);
2036:
2037: user->min=adjustuserrec(cfg, user->number, U_MIN, 10, amount);
2038:
2039: return(TRUE);
2040: }
2041:
2042: /****************************************************************************/
2043: /****************************************************************************/
2044: BOOL DLLCALL logoutuserdat(scfg_t* cfg, user_t* user, time_t now, time_t logontime)
2045: {
2046: char str[128];
2047: time_t tused;
2048: struct tm tm, tm_now;
2049:
2050: if(user==NULL)
2051: return(FALSE);
2052:
2053: if(now==0)
2054: now=time(NULL);
2055:
2056: tused=(now-logontime)/60;
2057: user->tlast=(ushort)(tused > USHRT_MAX ? USHRT_MAX : tused);
2058:
2059: putuserrec(cfg,user->number,U_LASTON,8,ultoa(now,str,16));
2060: putuserrec(cfg,user->number,U_TLAST,5,ultoa(user->tlast,str,10));
2061: adjustuserrec(cfg,user->number,U_TIMEON,5,user->tlast);
2062: adjustuserrec(cfg,user->number,U_TTODAY,5,user->tlast);
2063:
2064: /* Convert time_t to struct tm */
2065: if(localtime_r(&now,&tm_now)==NULL)
2066: return(FALSE);
2067:
2068: if(localtime_r(&logontime,&tm)==NULL)
2069: return(FALSE);
2070:
2071: /* Reset daily stats if new day */
2072: if(tm.tm_mday!=tm_now.tm_mday)
2073: resetdailyuserdat(cfg, user);
2074:
2075: return(TRUE);
2076: }
2077:
2078: /****************************************************************************/
2079: /****************************************************************************/
2080: void DLLCALL resetdailyuserdat(scfg_t* cfg, user_t* user)
2081: {
2082: char str[128];
2083:
2084: if(!VALID_CFG(cfg) || user==NULL)
2085: return;
2086:
2087: /* logons today */
2088: user->ltoday=0;
2089: putuserrec(cfg,user->number,U_LTODAY,5,"0");
2090: /* e-mails today */
2091: user->etoday=0;
2092: putuserrec(cfg,user->number,U_ETODAY,5,"0");
2093: /* posts today */
2094: user->ptoday=0;
2095: putuserrec(cfg,user->number,U_PTODAY,5,"0");
2096: /* free credits per day */
2097: user->freecdt=cfg->level_freecdtperday[user->level];
2098: putuserrec(cfg,user->number,U_FREECDT,10
2099: ,ultoa(user->freecdt,str,10));
2100: /* time used today */
2101: user->ttoday=0;
2102: putuserrec(cfg,user->number,U_TTODAY,5,"0");
2103: /* extra time today */
2104: user->textra=0;
2105: putuserrec(cfg,user->number,U_TEXTRA,5,"0");
2106: }
2107:
2108: /****************************************************************************/
2109: /****************************************************************************/
2110: char* DLLCALL usermailaddr(scfg_t* cfg, char* addr, char* name)
2111: {
2112: int i;
2113:
2114: if(!VALID_CFG(cfg) || addr==NULL || name==NULL)
2115: return(NULL);
2116:
2117: if(strchr(name,'@')!=NULL) { /* Avoid double-@ */
2118: strcpy(addr,name);
2119: return(addr);
2120: }
2121: if(strchr(name,'!') || (strchr(name,'.') && strchr(name,' ')))
2122: sprintf(addr,"\"%s\"@",name);
2123: else {
2124: sprintf(addr,"%s@",name);
2125: /* convert "first last@" to "first.last@" */
2126: for(i=0;addr[i];i++)
2127: if(addr[i]==' ' || addr[i]&0x80)
2128: addr[i]='.';
2129: strlwr(addr);
2130: }
2131: strcat(addr,cfg->sys_inetaddr);
2132: return(addr);
2133: }
2134:
2135: char* DLLCALL alias(scfg_t* cfg, char* name, char* buf)
2136: {
2137: char line[128];
2138: char* p;
2139: char* np;
2140: char* tp;
2141: char* vp;
2142: char fname[MAX_PATH+1];
2143: size_t namelen;
2144: size_t cmplen;
2145: FILE* fp;
2146:
2147: if(!VALID_CFG(cfg) || name==NULL || buf==NULL)
2148: return(NULL);
2149:
2150: p=name;
2151:
2152: sprintf(fname,"%salias.cfg",cfg->ctrl_dir);
2153: if((fp=fopen(fname,"r"))==NULL)
2154: return(name);
2155:
2156: while(!feof(fp)) {
2157: if(!fgets(line,sizeof(line),fp))
2158: break;
2159: np=line;
2160: SKIP_WHITESPACE(np);
2161: if(*np==';' || *np==0) /* no name value, or comment */
2162: continue;
2163: tp=np;
2164: FIND_WHITESPACE(tp);
2165:
2166: if(*tp==0) /* no alias value */
2167: continue;
2168: *tp=0;
2169:
2170: vp=tp+1;
2171: SKIP_WHITESPACE(vp);
2172: truncsp(vp);
2173: if(*vp==0) /* no value */
2174: continue;
2175:
2176: if(*np=='*') {
2177: np++;
2178: cmplen=strlen(np);
2179: namelen=strlen(name);
2180: if(namelen<cmplen)
2181: continue;
2182: if(strnicmp(np,name+(namelen-cmplen),cmplen))
2183: continue;
2184: if(*vp=='*')
2185: sprintf(buf,"%.*s%s",(int)(namelen-cmplen),name,vp+1);
2186: else
2187: strcpy(buf,vp);
2188: p=buf;
2189: break;
2190: }
2191: if(!stricmp(np,name)) {
2192: strcpy(buf,vp);
2193: p=buf;
2194: break;
2195: }
2196: }
2197: fclose(fp);
2198: return(p);
2199: }
2200:
2201: int DLLCALL newuserdat(scfg_t* cfg, user_t* user)
2202: {
2203: char str[MAX_PATH+1];
2204: char tmp[128];
2205: int c;
2206: int i;
2207: int err;
2208: int file;
2209: int unum=1;
2210: int last;
2211: long misc;
2212: FILE* stream;
2213: stats_t stats;
2214:
2215: if(!VALID_CFG(cfg) || user==NULL)
2216: return(-1);
2217:
2218: sprintf(str,"%suser/name.dat",cfg->data_dir);
2219: if(fexist(str)) {
2220: if((stream=fnopen(&file,str,O_RDONLY))==NULL) {
2221: return(errno);
2222: }
2223: last=filelength(file)/(LEN_ALIAS+2); /* total users */
2224: while(unum<=last) {
2225: fread(str,LEN_ALIAS+2,1,stream);
2226: for(c=0;c<LEN_ALIAS;c++)
2227: if(str[c]==ETX) break;
2228: str[c]=0;
2229: if(!c) { /* should be a deleted user */
2230: getuserrec(cfg,unum,U_MISC,8,str);
2231: misc=ahtoul(str);
2232: if(misc&DELETED) { /* deleted bit set too */
2233: getuserrec(cfg,unum,U_LASTON,8,str);
2234: if((time(NULL)-ahtoul(str))/86400>=cfg->sys_deldays)
2235: break; /* deleted long enough ? */
2236: }
2237: }
2238: unum++;
2239: }
2240: fclose(stream);
2241: }
2242:
2243: last=lastuser(cfg); /* Check against data file */
2244:
2245: if(unum>last+1) /* Corrupted name.dat? */
2246: unum=last+1;
2247: else if(unum<=last) { /* Overwriting existing user */
2248: getuserrec(cfg,unum,U_MISC,8,str);
2249: misc=ahtoul(str);
2250: if(!(misc&DELETED)) /* Not deleted? Set usernumber to end+1 */
2251: unum=last+1;
2252: }
2253:
2254: user->number=unum; /* store the new user number */
2255:
2256: if((err=putusername(cfg,user->number,user->alias))!=0)
2257: return(err);
2258:
2259: if((err=putuserdat(cfg,user))!=0)
2260: return(err);
2261:
2262: sprintf(str,"%sfile/%04u.in",cfg->data_dir,user->number); /* delete any files */
2263: delfiles(str,ALLFILES); /* waiting for user */
2264: rmdir(str);
2265: sprintf(tmp,"%04u.*",user->number);
2266: sprintf(str,"%sfile",cfg->data_dir);
2267: delfiles(str,tmp);
2268: sprintf(str,"%suser",cfg->data_dir);
2269: delfiles(str,tmp);
2270:
2271: sprintf(str,"%suser/ptrs/%04u.ixb",cfg->data_dir,user->number); /* msg ptrs */
2272: remove(str);
2273: sprintf(str,"%smsgs/%04u.msg",cfg->data_dir,user->number); /* delete short msg */
2274: remove(str);
2275:
2276: /* Update daily statistics database (for system and node) */
2277:
2278: for(i=0;i<2;i++) {
2279: sprintf(str,"%sdsts.dab",i ? cfg->ctrl_dir : cfg->node_dir);
2280: if((file=nopen(str,O_RDWR))==-1)
2281: continue;
2282: memset(&stats,0,sizeof(stats));
2283: lseek(file,4L,SEEK_SET); /* Skip timestamp */
2284: read(file,&stats,sizeof(stats));
2285: stats.nusers++;
2286: lseek(file,4L,SEEK_SET);
2287: write(file,&stats,sizeof(stats));
2288: close(file);
2289: }
2290:
2291: return(0);
2292: }
2293:
2294: /* Returns length of specified user record 'field', or -1 if invalid */
2295: int DLLCALL user_rec_len(int offset)
2296: {
2297: switch(offset) {
2298:
2299: /* Strings (of different lengths) */
2300: case U_ALIAS: return(LEN_ALIAS);
2301: case U_NAME: return(LEN_NAME);
2302: case U_HANDLE: return(LEN_HANDLE);
2303: case U_NOTE: return(LEN_NOTE);
2304: case U_COMP: return(LEN_COMP);
2305: case U_COMMENT: return(LEN_COMMENT);
2306: case U_NETMAIL: return(LEN_NETMAIL);
2307: case U_ADDRESS: return(LEN_ADDRESS);
2308: case U_LOCATION: return(LEN_LOCATION);
2309: case U_ZIPCODE: return(LEN_ZIPCODE);
2310: case U_PASS: return(LEN_PASS);
2311: case U_PHONE: return(LEN_PHONE);
2312: case U_BIRTH: return(LEN_BIRTH);
2313: case U_MODEM: return(LEN_MODEM);
2314:
2315: /* Internal codes (16 chars) */
2316: case U_CURSUB:
2317: case U_CURDIR:
2318: return (16);
2319:
2320: /* Dates in time_t format (8 hex digits) */
2321: case U_LASTON:
2322: case U_FIRSTON:
2323: case U_EXPIRE:
2324: case U_PWMOD:
2325: case U_NS_TIME:
2326: case U_LOGONTIME:
2327:
2328: /* 32-bit integers (8 hex digits) */
2329: case U_FLAGS1:
2330: case U_FLAGS2:
2331: case U_FLAGS3:
2332: case U_FLAGS4:
2333: case U_EXEMPT:
2334: case U_REST:
2335: case U_MISC:
2336: case U_QWK:
2337: case U_CHAT:
2338:
2339: /* Internal codes (8 chars) */
2340: case U_CURXTRN:
2341: case U_XEDIT:
2342: case U_SHELL:
2343: return(8);
2344:
2345: /* 16-bit integers (5 decimal digits) */
2346: case U_LOGONS:
2347: case U_LTODAY:
2348: case U_TIMEON:
2349: case U_TEXTRA:
2350: case U_TTODAY:
2351: case U_TLAST:
2352: case U_POSTS:
2353: case U_EMAILS:
2354: case U_FBACKS:
2355: case U_ETODAY:
2356: case U_PTODAY:
2357: case U_ULS:
2358: case U_DLS:
2359: return(5);
2360:
2361: /* 32-bit integers (10 decimal digits) */
2362: case U_ULB:
2363: case U_DLB:
2364: case U_CDT:
2365: case U_MIN:
2366: case U_FREECDT:
2367: return(10);
2368:
2369: /* 3 char strings */
2370: case U_TMPEXT:
2371: return(3);
2372:
2373: /* 2 digits integers (0-99) */
2374: case U_LEVEL:
2375: case U_TL:
2376: case U_ROWS:
2377: case U_LEECH: /* actually, 2 hex digits */
2378: return(2);
2379:
2380: /* Single digits chars */
2381: case U_SEX:
2382: case U_PROT:
2383: return(1);
2384: }
2385:
2386: return(-1);
2387: }
2388:
2389: BOOL DLLCALL is_download_free(scfg_t* cfg, uint dirnum, user_t* user)
2390: {
2391: if(!VALID_CFG(cfg))
2392: return(FALSE);
2393:
2394: if(dirnum>=cfg->total_dirs)
2395: return(FALSE);
2396:
2397: if(cfg->dir[dirnum]->misc&DIR_FREE)
2398: return(TRUE);
2399:
2400: if(user==NULL)
2401: return(FALSE);
2402:
2403: if(user->exempt&FLAG('D'))
2404: return(TRUE);
2405:
2406: if(cfg->dir[dirnum]->ex_ar==NULL || cfg->dir[dirnum]->ex_ar[0]==0)
2407: return(FALSE);
2408:
2409: return(chk_ar(cfg,cfg->dir[dirnum]->ex_ar,user));
2410: }
2411:
2412: /****************************************************************************/
2413: /* Add an IP address (with comment) to the IP filter/trashcan file */
2414: /* ToDo: Move somewhere more appropriate (filter.c?) */
2415: /****************************************************************************/
2416: BOOL DLLCALL filter_ip(scfg_t* cfg, char* prot, char* reason, char* host
2417: ,char* ip_addr, char* username, char* fname)
2418: {
2419: char ip_can[MAX_PATH+1];
2420: char tstr[64];
2421: FILE* fp;
2422: time_t now=time(NULL);
2423:
2424: if(ip_addr==NULL)
2425: return(FALSE);
2426:
2427: sprintf(ip_can,"%sip.can",cfg->text_dir);
2428: if(fname==NULL)
2429: fname=ip_can;
2430:
2431: if((fp=fopen(fname,"a"))==NULL)
2432: return(FALSE);
2433:
2434: fprintf(fp,"\n; %s %s by %s on %s\n"
2435: ,prot,reason,username,timestr(cfg,&now,tstr));
2436:
2437: if(host!=NULL)
2438: fprintf(fp,"; Hostname: %s\n",host);
2439:
2440: fprintf(fp,"%s\n",ip_addr);
2441:
2442: fclose(fp);
2443: return(TRUE);
2444: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.