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