1 #include <config.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <ctype.h>
5 
6 #ifdef HAVE_UNISTD_H
7 #include <unistd.h>
8 #endif
9 
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 
22 #ifdef HAVE_LIMITS_H
23 #include <limits.h>
24 #endif
25 
26 #include <string.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <errno.h>
30 #include <signal.h>
31 #include <sys/syslimits.h>
32 
33 #ifdef DMALLOC
34 #include <dmalloc.h>
35 #endif
36 
37 #include "suck_config.h"
38 #include "both.h"
39 #include "phrases.h"
40 /*----------------------------------------------------*/
41 typedef struct {
42 	char *group;
43 	unsigned int lownr;
44 	unsigned int highnr;
45 	char active;
46 } Group, *PGroup;
47 
48 /* Master Structure */
49 typedef struct {
50 	FILE *msgs;
51 	int nrgroups;
52 	int debug;
53 	int abort_exist; /* do we abort if article nr already exists */
54 	int link_type;
55 	PGroup groups;
56 	char active_file[PATH_MAX+1];
57 	const char *config_file;
58 	char basedir[PATH_MAX+1];
59 	const char *msgdir;
60 	const char *phrases;
61 } Master, *PMaster;
62 
63 enum { RETVAL_ERROR = -1, RETVAL_OK = 0 };
64 enum { LOCKFILE_LOCK, LOCKFILE_UNLOCK };
65 enum { LINK_SYM, LINK_HARD, LINK_NONE };
66 
67 #define NEWSGROUP "Newsgroups: "
68 #define NEWSGROUP_LEN 12
69 #define GROUP_SEP ','
70 #define CONFIG_BASE "BASE="
71 #define CONFIG_ACTIVE "ACTIVE="
72 #define CONFIG_BASE_LEN 5
73 #define CONFIG_ACTIVE_LEN 7
74 
75 /* for phrases stuff */
76 char **both_phrases = default_both_phrases;
77 char **lmove_phrases = default_lmove_phrases;
78 /*-------------------------------------------------------*/
79 /* function prototypes */
80 void scan_args(PMaster, int, char *[]);
81 void load_phrases(PMaster);
82 void free_phrases(void);
83 int load_active(PMaster);
84 int load_config(PMaster);
85 void free_active(PMaster);
86 int check_dirs(PMaster);
87 char *make_dirname(char *, char *);
88 int move_msgs(PMaster);
89 char *find_groups(PMaster, char *);
90 PGroup match_group(PMaster, char **);
91 int rewrite_active(PMaster);
92 int do_lockfile(PMaster, int);
93 /*--------------------------------------------------------------------------------*/
main(int argc,char * argv[])94 int main(int argc, char *argv[]) {
95 
96 	int retval = RETVAL_OK;
97 	const char *ptr;
98 	Master master;
99 
100 	/* set up defaults */
101 	master.msgs = stdout;
102 	master.nrgroups = 0;
103 	master.debug = 0;
104 	master.groups = NULL;
105 	strcpy(master.active_file,N_LMOVE_ACTIVE);
106 	master.config_file=N_LMOVE_CONFIG;
107 	master.phrases = NULL;
108 	master.basedir[0] = '\0';
109 	master.msgdir = NULL;
110 	master.abort_exist = TRUE;
111 	master.link_type = LINK_NONE;
112 
113 	scan_args(&master, argc, argv);
114 	load_phrases(&master);	/* this has to be here so rest prints okay */
115 
116 	/* have to load this first so get basedir */
117 	retval = load_config(&master);
118 
119 	if(master.debug == TRUE) {
120 		do_debug("master.active_file = %s\n", (master.active_file == NULL) ? "NULL" : master.active_file);
121 		do_debug("master.config_file = %s\n", (master.config_file == NULL) ? "NULL" : master.config_file);
122 		do_debug("master.basedir = %s\n", master.basedir);
123 		do_debug("master.msgdir = %s\n", (master.msgdir == NULL) ? "NULL" : master.msgdir);
124 		do_debug("master.phrases = %s\n", (master.phrases == NULL) ? "NULL" :master.phrases);
125 		ptr = "WHOOPS Wierd value for link_type";
126 		switch (master.link_type) {
127 		case LINK_SYM:
128 			ptr = "SYMBOLIC";
129 			break;
130 		case LINK_HARD:
131 			ptr = "HARD";
132 			break;
133 		case LINK_NONE:
134 			ptr = "NO LINKS";
135 			break;
136 		}
137 		do_debug("master.link_type = %s\n", ptr);
138 
139 	}
140 	if(master.basedir == NULL || master.basedir[0] == '\0') {
141 		error_log(ERRLOG_REPORT, lmove_phrases[5], NULL);
142 		retval = RETVAL_ERROR;
143 	}
144 	if(master.msgdir == NULL || master.msgdir[0] == '\0') {
145 		error_log(ERRLOG_REPORT, lmove_phrases[7], NULL);
146 		retval = RETVAL_ERROR;
147 	}
148 
149 	if(retval == RETVAL_OK) {
150 
151 #ifdef LOCKFILE
152 		if(do_lockfile(&master, LOCKFILE_LOCK) != RETVAL_OK) {
153 			retval = RETVAL_ERROR;
154 		}
155 		else {
156 #endif
157 			if((retval = load_active(&master)) == RETVAL_OK) {
158 				/* check to make sure all our directories are there */
159 				if((retval = check_dirs(&master)) == RETVAL_OK) {
160 					retval = move_msgs(&master);
161 					if(retval == RETVAL_OK) {
162 						retval = rewrite_active(&master);
163 					}
164 				}
165 			}
166 			free_active(&master);
167 #ifdef LOCKFILE
168 			do_lockfile(&master, LOCKFILE_UNLOCK);
169 		}
170 #endif
171 	}
172 	free_phrases();
173 	exit(retval);
174 }
175 /*-----------------------------------------------------------------------------------*/
rewrite_active(PMaster master)176 int rewrite_active(PMaster master) {
177 	/* move old active to active.old and write active */
178 	FILE *fpo;
179 	char fname[PATH_MAX+1];
180 	int i, retval = RETVAL_OK;
181 
182 	sprintf(fname, "%s.old", master->active_file);
183 	if(rename(master->active_file, fname) != 0) {
184 		MyPerror(fname);
185 		retval = RETVAL_ERROR;
186 	}
187 	else if((fpo = fopen(master->active_file, "w")) == NULL) {
188 		MyPerror(master->active_file);
189 		retval = RETVAL_ERROR;
190 	}
191 	else {
192 		for(i = 0; i < master->nrgroups && retval == RETVAL_OK ; i++) {
193 			if(fprintf(fpo, "%s %u %u %c\n", master->groups[i].group, master->groups[i].highnr, master->groups[i].lownr, master->groups[i].active) <= 0) {
194 				error_log(ERRLOG_REPORT, lmove_phrases[13], master->active_file, NULL);
195 				retval = RETVAL_ERROR;
196 			}
197 		}
198 		fclose(fpo);
199 		if(chmod(master->active_file, LMOVE_ACTIVE_MODE) != 0) {
200 			MyPerror(master->active_file);
201 		}
202 	}
203 	return retval;
204 }
205 /*-----------------------------------------------------------------------------------*/
move_msgs(PMaster master)206 int move_msgs(PMaster master) {
207 	/* go thru msg dir, and move the messages, based on "Newsgroups: subj line" */
208 	/* into newsgroup directory */
209 	struct dirent *entry;
210 	DIR *dptr;
211 	struct stat statbuf;
212 	char *ptr;
213 	PGroup group;
214 	char o_fname[PATH_MAX+1], n_fname[PATH_MAX+1];
215 	struct stat sbuf;
216 	int quit = FALSE, retval = RETVAL_OK, count;
217 	int (*linkit)(const char *, const char *);
218 
219 	/* which type of link will we create, symbolic or hard? Point to the right function */
220 	/* this won't get used if link_type is NONE, so we don't handle that case */
221 #ifdef EMX /* OS-2 doesn't have link or symlink */
222 	linkit = NULL;
223 	master->link_type = LINK_NONE;
224 #else
225 	linkit = (master->link_type == LINK_SYM) ? symlink : link;
226 #endif
227 
228 	if((dptr = opendir(master->msgdir)) == NULL) {
229 		MyPerror(master->msgdir);
230 		retval = RETVAL_ERROR;
231 	}
232 	else {
233 		while(((entry = readdir(dptr)) != NULL) && quit == FALSE) {
234 			sprintf(o_fname, "%s/%s", master->msgdir, entry->d_name);	/* build full path */
235 			if(stat(o_fname, &statbuf) == 0 && S_ISREG(statbuf.st_mode)) {
236 				if((ptr = find_groups(master, o_fname)) == NULL) {
237 					error_log(ERRLOG_REPORT, lmove_phrases[11], entry->d_name, NULL);
238 				}
239 				else {
240 					count = 0; /* how many groups have we matched */
241 					ptr += NEWSGROUP_LEN;	/* skip header */
242 					/* we pass a pointer to a pointer so that the subroutine can modify it */
243 					/* and return where we left off, so we can do multiple groups on one line */
244 					while(ptr != NULL && *ptr != '\0' && (group = match_group(master, &ptr)) != NULL) {
245 						count++;
246 						sprintf(n_fname, "%s/%d", make_dirname(master->basedir, group->group), group->highnr);
247 						if(stat(n_fname, &sbuf) == 0) {
248 							/* file exists */
249 							if(master->abort_exist == TRUE) {
250 								error_log(ERRLOG_REPORT, lmove_phrases[21], group->group, str_int(group->highnr), NULL);
251 								quit = TRUE;
252 							}
253 							else {
254 								while(stat(n_fname, &sbuf) == 0) {
255 									/* up it and try again */
256 									group->highnr++;
257 									sprintf(n_fname, "%s/%d", make_dirname(master->basedir, group->group), group->highnr);
258 								}
259 							}
260 						}
261 						if(quit != TRUE) {
262 							if(count == 1) {
263 								/* first group gets the file */
264 								if(rename(o_fname, n_fname) != 0) {
265 									error_log(ERRLOG_REPORT, lmove_phrases[13], o_fname, n_fname, NULL);
266 									MyPerror("");
267 								}
268 								else {
269 									if(master->debug == TRUE) {
270 										do_debug("Moved %s to %s\n", o_fname, n_fname, NULL);
271 									}
272 
273 									group->highnr++;
274 									strcpy(o_fname, n_fname); /* so we can link to this file */
275 								}
276 							}
277 							else if (master->link_type == LINK_NONE) {
278 								/* this will break the loop */
279 								ptr = NULL;
280 							}
281 							else {
282 								/* remainder of groups get links to first file */
283 								/* call the function reffed earlier */
284 								if(master->debug == TRUE) {
285 									do_debug("linking %s to %s\n", n_fname, o_fname, NULL);
286 								}
287 
288 								if((*linkit)(o_fname, n_fname) != 0) {
289 									MyPerror(n_fname);
290 								}
291 								else {
292 									group->highnr++;
293 								}
294 							}
295 						}
296 					}
297 					if(count == 0) {
298 						error_log(ERRLOG_REPORT, lmove_phrases[12], entry->d_name, NULL);
299 					}
300 				}
301 			}
302 		}
303 		closedir(dptr);
304 	}
305 
306 	return retval;
307 }
308 /*-----------------------------------------------------------------------------------*/
match_group(PMaster master,char ** newsgroups)309 PGroup match_group(PMaster master, char **newsgroups) {
310 	PGroup retval = NULL;
311 	int i;
312 	char *ptr, *eptr, save;
313         /* this gets a null-terminated line of newsgroups */
314 
315 	ptr = eptr = *newsgroups; /* this is a pointer to a pointer, so can do multiple groups per line */
316 
317 	/* in case the newsgroup line is formatted badly, and has extra spaces in the front */
318 	while (isspace(*ptr)) {
319 		ptr++;
320 		eptr++;
321 	}
322 	do {
323 		/* first find end of this group or NULL */
324 		/* the isspace handles the case where they use spaces either between */
325 		/* groups, or at the end of the line. */
326 		while(*eptr != GROUP_SEP && *eptr != '\0' && !isspace(*eptr) && *eptr) {
327 			eptr++;
328 		}
329 		save = *eptr;
330 		*eptr = '\0';	/* so can use ptr as group name */
331 
332 		for(i = 0 ; retval == NULL && i < master->nrgroups;i++) {
333 			if(strcmp(master->groups[i].group, ptr) == 0) {
334 				/* bingo */
335 				if(master->debug == TRUE) {
336 					do_debug("Matched group %s\n", ptr);
337 				}
338 				retval = &(master->groups[i]);
339 			}
340 		}
341 		ptr = ++eptr;	/* set up for next group */
342 	} while( save != '\0' && retval == NULL);
343 	/* the eptr -1 is because the ++eptr above puts us 1 beyond the EOL */
344 	if(retval == NULL) {
345 		/* if no matches , return EOL */
346 		*newsgroups = eptr -1;
347 	}
348 	else {
349 		/* if at end of line, return that, else return start of next group */
350 		*newsgroups  = (save == '\0') ? eptr-1 : eptr;
351 	}
352 	return retval;
353 }
354 /*-----------------------------------------------------------------------------------*/
find_groups(PMaster master,char * fname)355 char *find_groups(PMaster master, char *fname) {
356 	FILE *fpi;
357 	char *retval;
358 	static char linein[LMOVE_MAXLINLEN+1];
359 	int i;
360 
361 	retval = NULL;
362 	if((fpi = fopen(fname, "r")) == NULL) {
363 		MyPerror(fname);
364 	}
365 	else {
366 		while(retval == NULL && fgets(linein, LMOVE_MAXLINLEN, fpi) != NULL) {
367 			if(strncmp(linein, NEWSGROUP, NEWSGROUP_LEN) == 0) {
368 				retval = linein;
369 				/* now strip off NL off of EOL */
370 				i = strlen(linein) - 1;
371 				if(linein[i] == '\n') {
372 					linein[i] = '\0';
373 				}
374 				if(master->debug == TRUE) {
375 					do_debug("Found newsgroup line--%s--\n",linein, NULL);
376 				}
377 			}
378 		}
379 		fclose(fpi);
380 	}
381 	return retval;
382 }
383 /*-----------------------------------------------------------------------------------*/
load_config(PMaster master)384 int load_config(PMaster master) {
385 	int i, retval = RETVAL_OK;
386 	FILE *fpi;
387 	char linein[MAXLINLEN+1];
388 
389 	if((fpi = fopen(master->config_file, "r")) == NULL) {
390 		MyPerror(master->config_file);
391 		retval = RETVAL_ERROR;
392 	}
393 	else {
394 		while( fgets(linein, MAXLINLEN, fpi) != NULL) {
395 			/* strip the nl */
396 			i = strlen(linein);
397 			if(linein[i-1] == '\n') {
398 				linein[i-1] = '\0';
399 			}
400 
401 			if(strncmp(linein, CONFIG_BASE, CONFIG_BASE_LEN) == 0) {
402 				strcpy(master->basedir, &linein[CONFIG_BASE_LEN]);
403 			}
404 			else if(strncmp(linein, CONFIG_ACTIVE, CONFIG_ACTIVE_LEN) == 0) {
405 				strcpy(master->active_file, &linein[CONFIG_ACTIVE_LEN]);
406 			}
407 			else {
408 				error_log(ERRLOG_REPORT, lmove_phrases[20], NULL);
409 			}
410 		}
411 
412 		fclose(fpi);
413 	}
414 	return retval;
415 }
416 /*-----------------------------------------------------------------------------------*/
load_active(PMaster master)417 int load_active(PMaster master) {
418 	int i, j, retval = RETVAL_OK;
419 	unsigned int lownr, highnr;
420 	FILE *fpi;
421 	char linein[MAXLINLEN+1], group[MAXLINLEN+1], active_char;
422 
423 	/* each line in active is in the form group name high_msg_nr low_msg_nr  active_char */
424 
425 	if((fpi = fopen(master->active_file, "r")) == NULL) {
426 		MyPerror(master->active_file);
427 		retval = RETVAL_ERROR;
428 	}
429 	else {
430 		/* pass one, count the number of valid entries */
431 		/* and get the BASE dir and MSG dir entries */
432 		while((i = fscanf(fpi, "%s %u %u %c", linein,&highnr,&lownr,&active_char)) != EOF) {
433 			if(i == 4) {
434 				master->nrgroups++;
435 			}
436 			else {
437 				error_log(ERRLOG_REPORT, lmove_phrases[9], linein, NULL);
438 			}
439 		}
440 		if(master->debug == TRUE) {
441 			do_debug("Nr of groups in active = %d\n", master->nrgroups);
442 		}
443 		fseek(fpi, 0L, SEEK_SET);	/* rewind for pass two */
444 		/* pass two, put them into the master->groups array */
445 		if((master->groups = calloc(master->nrgroups, sizeof(Group))) == NULL) {
446 			error_log(ERRLOG_REPORT, lmove_phrases[8], NULL);
447 			retval = RETVAL_ERROR;
448 		}
449 		else {
450 			i = 0;
451 			while(retval == RETVAL_OK && fgets(linein, MAXLINLEN, fpi) != NULL) {
452 				if(sscanf(linein, "%s %u %u %c", group, &highnr, &lownr, &active_char) == 4) {
453 					if(highnr == 0) {
454 						highnr = 1;
455 					}	/* so we start at 1 */
456 					master->groups[i].lownr = lownr;
457 					master->groups[i].highnr = highnr;
458 					master->groups[i].active = active_char;
459 					/* now check for dupe groups */
460 					for(j = 0 ; j < i; j++) {
461 						if(strcmp(master->groups[j].group, group) == 0) {
462 							error_log(ERRLOG_REPORT, lmove_phrases[22], group, NULL);
463 							retval = RETVAL_ERROR;
464 							break; /* so we don't check any further */
465 						}
466 					}
467 					if((retval == RETVAL_OK) && ((master->groups[i].group = malloc(strlen(group)+1)) == NULL)) {
468 						error_log(ERRLOG_REPORT, lmove_phrases[8], NULL);
469 						retval = RETVAL_ERROR;
470 					}
471 					else {
472 						if(master->debug == TRUE) {
473 							do_debug("Group %d = %s\n", i, group);
474 						}
475 						strcpy(master->groups[i].group, group);
476 						i++;
477 					}
478 				}
479 			}
480 		}
481 		fclose(fpi);
482 	}
483 	return retval;
484 }
485 /*------------------------------------------------------------------------------------*/
free_active(PMaster master)486 void free_active(PMaster master) {
487 	int i;
488 	for(i=0;i<master->nrgroups;i++) {
489 		if(master->groups[i].group != NULL) {
490 			free(master->groups[i].group);
491 		}
492 	}
493 	free(master->groups);
494 	master->groups = NULL;
495 }
496 /*------------------------------------------------------------------------------------*/
check_dirs(PMaster master)497 int check_dirs(PMaster master) {
498 	/* check to make sure the base, msg, and all group dirs are available */
499 
500 	struct stat statbuf;
501 	int i, y, retval = RETVAL_OK;
502 	char *ptr, path[PATH_MAX+1];
503 
504 	if(stat(master->basedir, &statbuf) != 0 || ! S_ISDIR(statbuf.st_mode)) {
505 		error_log(ERRLOG_REPORT, lmove_phrases[10], master->basedir);
506 		retval = RETVAL_ERROR;
507 	}
508 	else if(stat(master->msgdir, &statbuf) != 0 || ! S_ISDIR(statbuf.st_mode)) {
509 		error_log(ERRLOG_REPORT, lmove_phrases[10], master->msgdir, NULL);
510 		retval = RETVAL_ERROR;
511 	}
512 	else {
513 		for(i = 0 ; i < master->nrgroups && retval == RETVAL_OK ; i++) {
514 			ptr = make_dirname(master->basedir, master->groups[i].group);
515 			if(master->debug == TRUE) {
516 				do_debug("Checking dir %s\n", ptr);
517 			}
518 			if(stat(ptr, &statbuf) != 0 && errno == ENOENT) {
519 				/* it don't exist. try to make it*/
520 				/* lets work our way down and try to make all dirs */
521 				sprintf(path, "%s/", master->basedir);
522 				y = strlen(path);		/* start at end of string */
523 				ptr = master->groups[i].group;
524 				while(retval == RETVAL_OK && *ptr != '\0') {
525 					/* copy til next dit or end */
526 					while(*ptr != '.' && *ptr != '\0') {
527 						path[y] = *ptr;
528 						y++;
529 						ptr++;
530 					}
531 					path[y] = '\0';	/* just to be on safe side */
532 					if(master->debug == TRUE) {
533 						do_debug("Trying to make dir %s : mode %o\n", path, LMOVE_DEFAULT_DIR_MODE);
534 					}
535 					umask(0);	/* so mode defined is mode we actually get */
536 					if(mkdir(path, LMOVE_DEFAULT_DIR_MODE) != 0 && errno != EEXIST) {
537 						MyPerror(path);
538 						retval = RETVAL_ERROR;
539 					}
540 					if(*ptr != '\0') {
541 						/* move on to next */
542 						path[y++] = '/';
543 						ptr++;
544 					}
545 				}
546 			}
547 			/* one final check */
548 			if(retval == RETVAL_OK) {
549 				/* have to redo stat, since we might have made dirs above */
550 				ptr = make_dirname(master->basedir, master->groups[i].group);
551 				if(stat(ptr, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
552 					error_log(ERRLOG_REPORT, lmove_phrases[10], ptr, NULL);
553 					retval = RETVAL_ERROR;
554 				}
555 			}
556 	 	}
557 	}
558 
559 	return retval;
560 }
561 /*------------------------------------------------------------------------------------*/
scan_args(PMaster master,int argc,char * argv[])562 void scan_args(PMaster master, int argc, char *argv[]) {
563 
564 	int loop;
565 
566 	for(loop = 1; loop < argc; loop++) {
567 		if(argv[loop][0] != '-' || argv[loop][2] != '\0') {
568 			error_log(ERRLOG_REPORT, lmove_phrases[0], argv[loop], NULL);
569 		}
570 		else {
571 			switch(argv[loop][1]) {
572 			case 'a':	/* active file */
573 				if(loop+1 == argc) {
574 					error_log(ERRLOG_REPORT, lmove_phrases[6], NULL);
575 				}
576 				else {
577 					strcpy(master->active_file,argv[++loop]);
578 				}
579 				break;
580 			case 'A': /* don't abort if article nr already exists on disk */
581 				master->abort_exist = FALSE;
582 				break;
583 			case 'c': /* config file */
584 				if(loop+1 == argc) {
585 					error_log(ERRLOG_REPORT, lmove_phrases[19], NULL);
586 				}
587 				else {
588 					master->config_file =argv[++loop];
589 				}
590 				break;
591 			case 'd': 	/* article directory */
592 				if(loop+1 == argc) {
593 					error_log(ERRLOG_REPORT, lmove_phrases[7], NULL);
594 				}
595 				else {
596 					master->msgdir = argv[++loop];
597 				}
598 				break;
599 			case 'D':	/* debug */
600 				master->debug = TRUE;
601 				break;
602 			case 'e':	/* use default error log path */
603 				error_log(ERRLOG_SET_FILE, ERROR_LOG,NULL);
604 				break;
605 			case 'E':	/* error log path */
606 				if(loop+1 == argc) {
607 					error_log(ERRLOG_REPORT, "%s\n",lmove_phrases[1],NULL);
608 				}
609 				else {
610 					error_log(ERRLOG_SET_FILE, argv[++loop], NULL);
611 				}
612 				break;
613 			case 'h':       /* use hard vice symbolic links */
614 				master->link_type = LINK_HARD;
615 				break;
616 			case 'l': 	/* language  phrase file */
617 				if(loop+1 == argc) {
618 					error_log(ERRLOG_REPORT, lmove_phrases[4],NULL);
619 				}
620 				else {
621 					master->phrases = argv[++loop];
622 				}
623 				break;
624 			case 's':       /* do symbolic links */
625 				master->link_type = LINK_SYM;
626 				break;
627 			default:
628 				error_log(ERRLOG_REPORT, lmove_phrases[0], argv[loop],NULL);
629 				break;
630 
631 			}
632 		}
633 	}
634 }
635 /*--------------------------------------------------------------------------------*/
make_dirname(char * base,char * group)636 char *make_dirname(char *base, char *group) {
637 	static char path[PATH_MAX+1];
638 	int i;
639 	char *ptr;
640 
641 	/* take base dir & a group name, change all "." in group to "/" */
642 	/* and return the full path */
643 	i = strlen(base);
644 	strcpy(path, base);
645 
646 	ptr = &path[i];
647 	sprintf(path, "%s/%s", base, group);
648 	while ( *ptr != '\0' ) {
649 		if(*ptr == '.') {
650 			*ptr = '/';
651 		}
652 		ptr++;
653 	}
654 	return path;
655 }
656 #ifdef LOCKFILE
657 /*--------------------------------------------------------------*/
do_lockfile(PMaster master,int option)658 int do_lockfile(PMaster master, int option) {
659 
660 	static char lockfile[PATH_MAX+1];
661 	int retval;
662 	FILE *f_lock;
663 	pid_t pid;
664 
665 	retval = RETVAL_OK;
666 	if(option == LOCKFILE_UNLOCK) {
667 		unlink(lockfile);
668 	}
669 	else {
670 		sprintf(lockfile, "%s/%s", master->basedir, N_LMOVE_LOCKFILE);
671 		if((f_lock = fopen(lockfile, "r")) != NULL) {
672 			/* okay, let's try and see if this sucker is truly alive */
673 			long tmp = 0;
674 			fscanf(f_lock, "%ld", &tmp);
675 			fclose(f_lock);
676 			pid = (pid_t)tmp;
677 			if(pid <= 0) {
678 				error_log(ERRLOG_REPORT,  lmove_phrases[14], lockfile, NULL);
679 				retval = RETVAL_ERROR;
680 			}
681 			/* this next technique borrowed from pppd, sys-linux.c (ppp2.2.0c) */
682 			/* if the pid doesn't exist (can't send any signal to it), then try */
683 			/* to remove the stale PID file so can recreate it. */
684 			else if(kill(pid, 0) == -1 && errno == ESRCH) {
685 				/* no pid found */
686 				if(unlink(lockfile) == 0) {
687 					/* this isn't error so don't put in error log */
688 					print_phrases(master->msgs, lmove_phrases[15], lockfile, NULL);
689 				}
690 				else {
691 					error_log(ERRLOG_REPORT, lmove_phrases[16], lockfile, NULL);
692 					retval = RETVAL_ERROR;
693 				}
694 			}
695 			else {
696 				error_log(ERRLOG_REPORT, lmove_phrases[17], lockfile,  NULL);
697 				retval = RETVAL_ERROR;
698 			}
699 		}
700 		if(retval == RETVAL_OK) {
701 			if((f_lock = fopen(lockfile, "w")) != NULL) {
702 				fprintf(f_lock, "%ld", (long) getpid());
703 				fclose(f_lock);
704 			}
705 			else {
706 				error_log(ERRLOG_REPORT, lmove_phrases[18],  lockfile, NULL);
707 				retval = RETVAL_ERROR;
708 			}
709 		}
710 	}
711 	return retval;
712 }
713 #endif
714 
715 /*--------------------------------------------------------------------------------*/
716 /* THE strings in this routine is the only one not in the arrays, since           */
717 /* we are in the middle of reading the arrays, and they may or may not be valid.  */
718 /*--------------------------------------------------------------------------------*/
load_phrases(PMaster master)719 void load_phrases(PMaster master) {
720 
721 	int error=TRUE;
722 	FILE *fpi;
723 	char buf[MAXLINLEN];
724 
725 
726 	if(master->phrases != NULL) {
727 
728 		if((fpi = fopen(master->phrases, "r")) == NULL) {
729 			MyPerror(master->phrases);
730 		}
731 		else {
732 			fgets(buf, MAXLINLEN, fpi);
733 			if(strncmp( buf, SUCK_VERSION, strlen(SUCK_VERSION)) != 0) {
734 				error_log(ERRLOG_REPORT, "Invalid Phrase File, wrong version\n", NULL);
735 			}
736 			else if((both_phrases = read_array(fpi, NR_BOTH_PHRASES, TRUE)) != NULL) {
737 				read_array(fpi, NR_RPOST_PHRASES, FALSE); /* skip these */
738 				read_array(fpi, NR_TEST_PHRASES, FALSE);
739 				read_array(fpi, NR_SUCK_PHRASES, FALSE);
740 				read_array(fpi, NR_TIMER_PHRASES, FALSE);
741 				read_array(fpi, NR_CHKH_PHRASES, FALSE);
742 				read_array(fpi, NR_DEDUPE_PHRASES, FALSE);
743 				read_array(fpi, NR_KILLF_REASONS, FALSE);
744 				read_array(fpi, NR_KILLF_PHRASES, FALSE);
745 				read_array(fpi, NR_KILLP_PHRASES, FALSE);
746 				if((lmove_phrases = read_array(fpi, NR_LMOVE_PHRASES, TRUE)) != NULL) {
747 					error = FALSE;
748 				}
749 			}
750 		}
751 		fclose(fpi);
752 		if(error == TRUE) {
753 			/* reset back to default */
754 			error_log(ERRLOG_REPORT, "Using default Language phrases\n",NULL);
755 			lmove_phrases = default_lmove_phrases;
756 			both_phrases = default_both_phrases;
757 		}
758 	}
759 }
760 /*--------------------------------------------------------------------------------*/
free_phrases(void)761 void free_phrases(void) {
762 		/* free up the memory alloced in load_phrases() */
763 		if(lmove_phrases != default_lmove_phrases) {
764 			free_array(NR_LMOVE_PHRASES, lmove_phrases);
765 		}
766 		if(both_phrases != default_both_phrases) {
767 			free_array(NR_BOTH_PHRASES, both_phrases);
768 		}
769 
770 }
771