1 #include <config.h>
2
3 #include <stdio.h>
4 #ifdef HAVE_UNISTD_H
5 #include <unistd.h>
6 #endif
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <errno.h>
10 #ifdef HAVE_DIRENT_H
11 # include <dirent.h>
12 #else
13 # define dirent direct
14 # ifdef HAVE_SYS_NDIR_H
15 # include <sys/ndir.h>
16 # endif
17 # ifdef HAVE_SYS_DIR_H
18 # include <sys/dir.h>
19 # endif
20 #endif
21 #ifdef HAVE_LIMITS_H
22 #include <limits.h>
23 #endif
24 #include <string.h>
25 #include <signal.h>
26 #include <sys/param.h>
27 #include <ctype.h>
28
29 #ifdef DMALLOC
30 #include <dmalloc.h>
31 #endif
32
33 #include "suck_config.h"
34 #include "suck.h"
35 #include "both.h"
36 #include "suckutils.h"
37 #include "phrases.h"
38
39 /*------------------------------------------------------------------------*/
40 /* check if directory exists, if not, try to create it. */
41 /* return TRUE if made/exists and can write to it */
42 /* -----------------------------------------------------------------------*/
checkdir(const char * dirname)43 int checkdir(const char *dirname) {
44
45 struct stat buf;
46 int retval = TRUE;
47
48 if(stat(dirname, &buf)== 0) {
49 /* it exists */
50 if(!S_ISDIR(buf.st_mode)) {
51 error_log(ERRLOG_REPORT, sucku_phrases[0], dirname, NULL);
52 retval = FALSE;
53 }
54 else if(access(dirname, W_OK) != 0) {
55 error_log(ERRLOG_REPORT, sucku_phrases[1], dirname, NULL);
56 retval = FALSE;
57 }
58 }
59 else if(errno == ENOENT) {
60 /* doesn't exist, make it */
61 if(mkdir(dirname, (S_IRUSR | S_IWUSR | S_IXUSR)) != 0) {
62 MyPerror(dirname);
63 retval = FALSE;
64 }
65 }
66 else {
67 /* huh? */
68 MyPerror(dirname);
69 retval = FALSE;
70 }
71 return retval;
72 }
73 /*--------------------------------------------------------------*/
74 /* if which = FP_SET, store directory in array */
75 /* = FP_GET, retrieve directory and add file name */
76 /* = FP_GET_NOPOSTFIX, get without appending postfix */
77 /* = FP_GET_POSTFIX, get ONLY the postfix */
78 /* retval FP_SET, if valid dir, the dir, else NULL */
79 /* FP_GET, full path */
80 /* FP_GET_POSTFIX, only the postfix */
81 /*--------------------------------------------------------------*/
full_path(int which,int dir,const char * fname)82 const char *full_path(int which, int dir, const char *fname) {
83
84 static char dirs[FP_NR_DIRS][PATH_MAX+1] = { N_TMPDIR, N_DATADIR, N_MSGDIR };
85 static char path[PATH_MAX+1]; /* static so area valid after return */
86 static char postfix[PATH_MAX+1] = { "\0" };
87
88 char *retptr;
89 int ok, i;
90
91 retptr = NULL;
92
93 switch(which) {
94 case FP_GET:
95 case FP_GET_NOPOSTFIX:
96 /* put the right directory as the first part of the path */
97 strcpy(path, dirs[dir]);
98 /* if it contains a dit, then change to full path */
99 if(path[0] == '.') {
100 path[0] = '\0';
101 if(getcwd(path, PATH_MAX) == NULL) {
102 MyPerror(path);
103 /* restore current path and pray */
104 /* it will work later */
105 strcpy(path, dirs[dir]);
106 }
107 else {
108 /* tack on remainder of path */
109 /* the 1 so skip . */
110 strcat(path, &dirs[dir][1]);
111 }
112 }
113 if(fname != NULL && fname[0] != '\0') {
114 i = strlen(path);
115 /* if nothing to put on don't do any of this */
116 /* put on trailing slant bar if needed */
117 if(path[i-1] != '/') {
118 path[i++] = '/';
119 path[i] = '\0'; /* null terminate it */
120 }
121 /* finally, put on filename */
122 strcpy(&path[i], fname);
123
124 if(which != FP_GET_NOPOSTFIX && postfix[0] != '\0') {
125 strcat(path, postfix);
126 }
127 }
128 retptr = path;
129 break;
130 case FP_SET_POSTFIX:
131 ok = TRUE;
132 strncpy(postfix, fname, sizeof(postfix));
133 break;
134 case FP_GET_POSTFIX:
135 retptr = postfix;
136 break;
137 case FP_SET:
138 ok = TRUE;
139 switch(dir) {
140 case FP_TMPDIR:
141 if(access(fname, W_OK) == -1) {
142 MyPerror(fname);
143 ok = FALSE;
144 }
145 break;
146 case FP_DATADIR:
147 if(access(fname, R_OK) == -1) {
148 MyPerror(fname);
149 ok = FALSE;
150 }
151 break;
152 case FP_MSGDIR: /* do_nothing, this is checked elsewhere */
153 break;
154 }
155 if(ok == FALSE) {
156 retptr = NULL;
157 }
158 else {
159 strncpy(dirs[dir], fname, sizeof(dirs[0]));
160 retptr = dirs[dir];
161 }
162 break;
163 }
164 return retptr;
165 }
166 #ifdef LOCKFILE
167 /*--------------------------------------------------------------*/
do_lockfile(PMaster master)168 int do_lockfile(PMaster master) {
169
170 int retval;
171 FILE *f_lock;
172 const char *lockfile;
173 pid_t pid;
174
175 retval = RETVAL_OK;
176
177 lockfile = full_path(FP_GET, FP_TMPDIR, N_LOCKFILE);
178 if((f_lock = fopen(lockfile, "r")) != NULL) {
179 /* okay, let's try and see if this sucker is truly alive */
180 long tmp = 0;
181 fscanf(f_lock, "%ld", &tmp);
182 fclose(f_lock);
183 pid = (pid_t)tmp;
184 if(pid <= 0) {
185 error_log(ERRLOG_REPORT, sucku_phrases[2], lockfile, NULL);
186 retval = RETVAL_ERROR;
187 }
188 /* this next technique borrowed from pppd, sys-linux.c (ppp2.2.0c) */
189 /* if the pid doesn't exist (can't send any signal to it), then try */
190 /* to remove the stale PID file so can recreate it. */
191 else if(kill(pid, 0) == -1 && errno == ESRCH) {
192 /* no pid found */
193 if(unlink(lockfile) == 0) {
194 /* this isn't error so don't put in error log */
195 print_phrases(master->msgs, sucku_phrases[3], lockfile, NULL);
196 }
197 else {
198 error_log(ERRLOG_REPORT, sucku_phrases[4], lockfile, NULL);
199 retval = RETVAL_ERROR;
200 }
201 }
202 else {
203 error_log(ERRLOG_REPORT, sucku_phrases[5], lockfile, NULL);
204 retval = RETVAL_ERROR;
205 }
206 }
207 if(retval == RETVAL_OK) {
208 if((f_lock = fopen(lockfile, "w")) != NULL) {
209 fprintf(f_lock, "%ld", (long) getpid());
210 fclose(f_lock);
211 }
212 else {
213 error_log(ERRLOG_REPORT, sucku_phrases[6], lockfile, NULL);
214 retval = RETVAL_ERROR;
215 }
216 }
217 return retval;
218 }
219 #endif
220 /*-------------------------------------------------------------------------*/
qcmp_msgid(const char * nr1,const char * nr2)221 int qcmp_msgid(const char *nr1, const char *nr2) {
222 /* return -1 if a < b, 0 if a == b, 1 if a > b */
223
224 int retval = 0;
225
226 /* cmp two article id numbers */
227 /* which is <xxxxxxxxxxxxxxxxx@place.org */
228 /* use case sensitive compares up to the @ */
229 /* then use case insensitive compares on the organization */
230 /* this is to conform to rfc822 */
231
232 if(nr1 != NULL && nr2 != NULL) {
233 while ( *nr1 == *nr2 && *nr1 != '\0' && *nr1 != '@') {
234 nr1++;
235 nr2++;
236 }
237 if(*nr1 == '@') {
238 while( tolower(*nr1) == tolower(*nr2) && *nr1 != '\0') {
239 nr1++;
240 nr2++;
241 }
242 }
243 if(*nr1 == *nr2 && *nr1 == '\0') {
244 retval = 0;
245 }
246 else if(*nr1 != *nr2) {
247 retval = ( *nr1 < *nr2 ) ? -1 : 1;
248 }
249 else {
250 /* one is longer than the other */
251 retval = (*nr1 == '\0') ? -1 : 1;
252 }
253 }
254 return retval;
255 }
256 /*------------------------------------------------------------------------------*/
cmp_msgid(const char * nr1,const char * nr2)257 int cmp_msgid(const char *nr1, const char *nr2) {
258 /* cmp two article id numbers */
259 /* which is <xxxxxxxxxxxxxxxxx@place.org> */
260 /* use case sensitive compares up to the @ */
261 /* then use case insensitive compares on the organization */
262 /* this is to conform to rfc822 */
263 int retval = FALSE;
264
265 if(nr1 != NULL && nr2 != NULL) {
266
267 while ( *nr1 == *nr2 && *nr1 != '\0' && *nr1 != '@') {
268 nr1++;
269 nr2++;
270 }
271 if(*nr1 == '@') {
272 while( tolower(*nr1) == tolower(*nr2) && *nr1 != '\0') {
273 nr1++;
274 nr2++;
275 }
276 }
277 if(*nr1 == *nr2 && *nr1 == '\0') {
278 retval = TRUE;
279 }
280 }
281 return retval;
282
283 }
284 /*-----------------------------------------------------------------------------*/
285 /* move a file from one location to another */
286 /*-----------------------------------------------------------------------------*/
move_file(const char * src,const char * dest)287 int move_file(const char *src, const char *dest) {
288
289 char block[MAXLINLEN];
290 FILE *fpi, *fpo;
291 int retval = RETVAL_OK;
292 size_t nrread;
293
294
295
296 /* first try the easy way */
297 if(src == NULL || dest == NULL) {
298 error_log(ERRLOG_REPORT, sucku_phrases[9], NULL);
299 retval = RETVAL_ERROR;
300 }
301 else if(rename(src, dest) != 0) {
302 #ifdef EMX
303 if(errno != EACCES) {
304 MyPerror(src);
305 retval = RETVAL_ERROR;
306 }
307 #else
308 if(errno != EXDEV) {
309 MyPerror(src);
310 retval = RETVAL_ERROR;
311 }
312 #endif
313 else {
314 /* can't rename, try to copy file */
315 if((fpi = fopen(src, "r")) == NULL) {
316 MyPerror(src);
317 retval = RETVAL_ERROR;
318 }
319 else if(( fpo = fopen(dest, "w")) == NULL) {
320 fclose(fpi);
321 MyPerror(dest);
322 retval = RETVAL_ERROR;
323 }
324 else {
325 while(retval == RETVAL_OK && (nrread = fread(block, sizeof(char), MAXLINLEN, fpi)) > 0) {
326 if(fwrite(block, sizeof(char), nrread, fpo) != nrread) {
327 error_log(ERRLOG_REPORT, sucku_phrases[7], dest, NULL);
328 retval = RETVAL_ERROR;
329 }
330 }
331 if(ferror(fpi) != 0) {
332 error_log(ERRLOG_REPORT, sucku_phrases[8], src, NULL) ;
333 }
334 fclose(fpi);
335 fclose(fpo);
336 }
337 /* now that copy is successful, nuke it */
338 if(retval == RETVAL_OK) {
339 unlink(src);
340 }
341 }
342 }
343 return retval;
344 }
345