1 /* $Id$
2  *  Provides function to generate strong unique 32-bit number uses in FTN MSGID
3  *  (message ID)
4  *  Written at 2002 by Pavel Goulchuck 2:463/68 pgul@pgul.kiev.ua
5  *
6  * HUSKYLIB: common defines, types and functions for HUSKY
7  *
8  * This is part of The HUSKY Fidonet Software project:
9  * see http://husky.sourceforge.net for details
10  *
11  *
12  * HUSKYLIB is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * HUSKYLIB is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; see file COPYING. If not, write to the
24  * Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25  *
26  * See also http://www.gnu.org, license may be found here.
27  */
28 
29 /* standard headers */
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <time.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 
39 /* huskylib: compiler.h */
40 #include <compiler.h>
41 
42 /* standard headers */
43 #ifdef HAS_IO_H
44 #   include <io.h>
45 #endif
46 
47 #ifdef HAS_STRINGS_H
48 #   include <strings.h>
49 #endif
50 
51 /* huskylib headers */
52 #define DLLEXPORT
53 #include <huskyext.h>
54 
55 #include <huskylib.h>
56 
57 
58 #define MAX_OUTRUN	(3ul*365*24*60*60) /* 3 year */
59 
60 #define GenMsgIdErr(a) { if (errstr!=NULL) { *errstr = a; } }
61 
62 char genmsgid_rev[]  = "$Revision$";
63 char genmsgid_date[] = "$Date$";
64 
oldGenMsgId(void)65 dword oldGenMsgId(void)
66 {
67 	dword seq = (dword)time(NULL);
68 	sleep(1);
69 	return seq;
70 }
71 
GenMsgIdEx(char * seqdir,unsigned long max_outrun,dword (* altGenMsgId)(void),char ** errstr)72 dword _XPENTRY GenMsgIdEx(char *seqdir, unsigned long max_outrun, dword (*altGenMsgId)(void), char **errstr)
73 {
74 	dword seq, n, curtime;
75 	FFIND *ff;
76 	char *seqpath, max_fname[13], *new_fname, *pname, *p;
77 	int  h, n_try;
78 
79 	if (altGenMsgId == NULL)
80 		altGenMsgId = oldGenMsgId;
81 	GenMsgIdErr(NULL);
82 
83 	if (seqdir == NULL || *seqdir == '\0') {
84 		seqdir = getenv("SEQDIR");
85 		if (seqdir == NULL || *seqdir == '\0') {
86 			/* warning: no SEQDIR defined, fall to ugly old algorythm */
87 			GenMsgIdErr("no SEQDIR defined");
88 			return (*altGenMsgId)();
89 		}
90 	}
91 	seqpath = malloc(strlen(seqdir)+13);
92 	strcpy(seqpath, seqdir);
93 	pname = seqpath + strlen(seqpath);
94 	if (*seqpath && strchr("/\\", seqpath[strlen(seqpath)-1]) == NULL)
95 		*pname++ = PATH_DELIM;
96 	new_fname = NULL;
97 	if (max_outrun == 0) {
98 		p = getenv("SEQOUT");
99 		if ( p && isdigit((int)(*p)) ) {
100 			max_outrun = (unsigned long)atol(p);
101 			switch (tolower(p[strlen(p) - 1])) {
102 				case 'y':	max_outrun *= 365;
103 				case 'd':	max_outrun *= 24;
104 				case 'h':	max_outrun *= 60*60;
105 						break;
106 				case 'w':	max_outrun *= (7l*24*60*60);
107 						break;
108 				case 'm':	max_outrun *= (31l*24*60*60);
109 						break;
110 			}
111 		}
112 		else max_outrun = MAX_OUTRUN;
113 	}
114 	for (n_try=0;;n_try++) {
115 		curtime = (dword)time(NULL);
116 		seq = 0;
117 		max_fname[0] = '\0';
118 		strcpy(pname, "*.*");
119 		ff = FFindInfo(seqpath);
120 		if (ff == NULL) { /* file not found */
121 			*pname = '\0';
122 			if (n_try == 0) {
123 				if (direxist(seqpath))
124 					goto emptydir; /* directory exist & empty */
125 				else if (_createDirectoryTree(seqpath) == 0)
126 					goto emptydir; /* directory created */
127 			} /* if directory not created at 1st time then use old alghorithm */
128 			free(seqpath);
129 			if (new_fname) free(new_fname);
130 			GenMsgIdErr("can't open/create SEQDIR directory");
131 			return (*altGenMsgId)();
132 		}
133 		do {
134 			for (p=ff->ff_name; isxdigit((int)(*p)); p++);
135 			if (stricmp(p, ".seq") != 0) continue;
136 			if (strlen(ff->ff_name) > 12) continue;
137 			n = strtol(ff->ff_name, NULL, 16);
138 			if (n > curtime && n - curtime > max_outrun) {
139 				/* counter too large, remove */
140 				strcpy(pname, ff->ff_name);
141 				unlink(seqpath);
142 				continue;
143 			}
144 			if (n >= seq) {
145 				if (max_fname[0]) {
146 					strcpy(pname, max_fname);
147 					unlink(seqpath);
148 				}
149 				strcpy(max_fname, ff->ff_name);
150 				seq = n;
151 			} else {
152 				strcpy(pname, ff->ff_name);
153 				unlink(seqpath);
154 			}
155 		} while (FFindNext(ff) == 0);
156 		if (ff) FFindClose(ff);
157 emptydir:
158 		if (seq < curtime) seq = curtime;
159 		if (new_fname == NULL)
160 			new_fname = malloc(strlen(seqpath) + 13);
161 		*pname = '\0';
162 		sprintf(new_fname, "%s%08lx.seq", seqpath, (unsigned long)(seq + 1));
163 		if (max_fname[0] == '\0') {
164 			/* No files found, create new */
165 			h = open(new_fname, O_CREAT|O_BINARY|O_EXCL, 0666);
166 			if (h != -1) {
167 				/* ok, scan again */
168 				close(h);
169 				continue;
170 			}
171 			/* error creating file */
172 			if (errno == EEXIST) continue;
173 			free(seqpath);
174 			free(new_fname);
175 			GenMsgIdErr("error creating file in SEQDIR directory");
176 			return (*altGenMsgId)();
177 		}
178 		/* rename max_fname to new_fname */
179 		strcpy(pname, max_fname);
180 		if (rename(seqpath, new_fname) == 0) {
181 			free(seqpath);
182 			free(new_fname);
183 			return seq;
184 		}
185 		if (errno == ENOENT || errno == EEXIST ||
186 		    ((errno == EPERM || errno == EACCES) && n_try < 16))
187 			continue;
188 		free(seqpath);
189 		free(new_fname);
190 		GenMsgIdErr("can't rename .seq file");
191 		return (*altGenMsgId)();
192 	}
193 }
194 
GenMsgId(char * seqdir,unsigned long max_outrun)195 dword _XPENTRY GenMsgId(char *seqdir, unsigned long max_outrun)
196 {
197   return GenMsgIdEx(seqdir, max_outrun, NULL, NULL);
198 }
199