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