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