1 #include <config.h>
2 
3 #include <stdio.h>
4 #include <stdlib.h>
5 
6 #ifdef HAVE_UNISTD_H
7 #include <unistd.h>
8 #include <sys/types.h>
9 #endif
10 
11 #include <netdb.h>
12 #include <ctype.h>
13 #include <string.h>
14 #include <netinet/in.h>
15 #include <sys/socket.h>
16 #ifdef HAVE_ARPA_INET_H
17 #include <arpa/inet.h>
18 #endif
19 #ifdef HAVE_NET_SOCKET_H
20 #include <net/socket.h>
21 #endif
22 #include <errno.h>
23 #include <stdarg.h>
24 
25 #ifdef HAVE_LIMITS_H
26 #include <limits.h>
27 #endif
28 
29 #ifdef DMALLOC
30 #include <dmalloc.h>
31 #endif
32 
33 #include "suck_config.h"
34 #include "both.h"
35 #include "phrases.h"
36 
37 #ifdef TIMEOUT
38 /*------------------------------------*/
39 int TimeOut = TIMEOUT;
40 /* yes, this is the lazy way out, but */
41 /* there are too many routines that   */
42 /* call sgetline() to modify em all   */
43 /*------------------------------------*/
44 # if TIME_WITH_SYS_TIME
45 #  include <sys/time.h>
46 #  include <time.h>
47 # else
48 #  if HAVE_SYS_TIME_H
49 #    include <sys/time.h>
50 #  else
51 #    include <time.h>
52 #  endif
53 # endif
54 #endif /* TIMEOUT */
55 
56 #ifdef MYSIGNAL
57 #include <signal.h>
58 #endif
59 
60 #ifdef HAVE_SYS_SELECT_H
61 #include <sys/select.h>		/* for aix */
62 #endif
63 
64 #ifdef HAVE_LIBSSL
65 #include <openssl/ssl.h>
66 #endif
67 
68 /* internal function proto */
69 void vprint_phrases(FILE *, const char *, va_list);
70 void do_debug_vl(const char *, va_list);
71 void convert_nl(char *);
72 char *findnl(char *, char *);
73 
74 /*-----------------------------------------------------*/
75 /* get next number in string */
number(char * sp,int * intPtr)76 char *number(char *sp, int *intPtr) {
77 	int start, end;
78 	char c;
79 	char *retval;
80 
81 	if(sp==NULL) {
82 		*intPtr=0;
83 		retval = sp;
84 	}
85 	else {
86 		/* skip any leading spaces */
87 		start = 0;
88 		while(sp[start] == ' ') {
89 			start++;
90 		}
91 		end = start;
92 		while(isdigit(sp[end])) {
93 			end++;
94 		}
95 		/* now we have the numbers width*/
96 
97 		c=sp[end];	/* save off the character */
98 		sp[end]='\0';	/* truncate nr so sscanf works right */
99 		sscanf(&sp[start],"%d",intPtr);
100 		sp[end]=c;	/* restore it back */
101 
102 		/* if at EOS return the NULL, else skip space */
103 		retval = (sp[end] == '\0') ? sp+end : sp+(++end);
104 	}
105 	return retval;
106 }
107 /*----------------------------------------------------*/
108 /* identical to above, except it gets a long vice int */
get_long(char * sp,long * intPtr)109 char *get_long(char *sp, long *intPtr) {
110 	int start, end;
111 	char c;
112 	char *retval;
113 
114 	if(sp==NULL) {
115 		*intPtr=0;
116 		retval = sp;
117 	}
118 	else {
119 		/* skip any leading spaces */
120 		start = 0;
121 		while(sp[start] == ' ') {
122 			start++;
123 		}
124 		end = start;
125 		while(isdigit(sp[end])) {
126 			end++;
127 		}
128 		/* now we have the numbers width*/
129 
130 		c=sp[end];	/* save off the character */
131 		sp[end]='\0';	/* truncate nr so sscanf works right */
132 		sscanf(&sp[start],"%ld",intPtr);
133 		sp[end]=c;	/* restore it back */
134 
135 		/* if at EOS return the NULL, else skip space */
136 		retval = (sp[end] == '\0') ? sp+end : sp+(++end);
137 	}
138 	return retval;
139 }
140 
141 /*---------------------------------------------*/
get_addrinfo(const char * host,const char * sport)142 struct addrinfo *get_addrinfo(const char *host, const char *sport) {
143 	struct addrinfo hints = { .ai_socktype=SOCK_STREAM, .ai_flags = AI_CANONNAME };
144 	struct addrinfo * res = NULL;
145 
146 	if(host==NULL) {
147 		error_log(ERRLOG_REPORT,both_phrases[0], NULL);
148 	}
149 	else {
150 		int st = getaddrinfo(host, sport, &hints, &res);
151 		if (st < 0) {
152 			error_log(ERRLOG_REPORT, "%v1%: %v2%: %v3%\n", host, both_phrases[2], gai_strerror(st), NULL);
153 		}
154 	}
155 	return res;
156 }
157 /*--------------------------------------------*/
connect_to_nntphost(const char * host,char * name,size_t namelen,FILE * msgs,unsigned short int portnr,int do_ssl,void ** ssl)158 int connect_to_nntphost(const char *host, char * name, size_t namelen, FILE *msgs, unsigned short int portnr, int do_ssl, void **ssl) {
159 	char *realhost;
160 	char sport[10];
161 	int sockfd = -1;
162 	struct addrinfo * ai;
163 	char buffer[60]; // if not given by caller. NI_MAXHOST would be better, but that's ok as well.
164 
165 	if (host == NULL) {
166 		error_log(ERRLOG_REPORT, both_phrases[0], NULL);
167 		return sockfd;
168 	}
169 
170 #ifdef HAVE_LIBSSL
171 	SSL *ssl_struct = NULL;
172 	SSL_CTX *test1 = NULL;
173 
174 	if(do_ssl == TRUE) {
175 		(void) SSL_library_init();
176 		test1 = SSL_CTX_new(SSLv23_client_method());
177 		if(test1 == NULL) {
178 			/* whoops */
179 			error_log(ERRLOG_REPORT, both_phrases[18], NULL);
180 			return sockfd;
181 		}
182 	}
183 #endif
184 	if (!name) {
185 		name = buffer;
186 		namelen = sizeof buffer;
187 	}
188 	/* handle host:port type syntax */
189 	realhost = strdup(host);
190 	if(realhost == NULL) {
191 		MyPerror("out of memory copying host name");
192 		return sockfd;
193 	}
194 	char * ptr = strchr(realhost, ':');
195 	if(ptr != NULL) {
196 		*ptr = '\0';  /* null terminate host name */
197 		portnr = atoi(++ptr); /* get port number */
198 	}
199 
200 
201 
202 	sprintf(sport, "%hu", portnr);	/* cause print_phrases wants all strings */
203 	print_phrases(msgs, both_phrases[1], sport, NULL);
204 
205 	/* Find the internet addresses of the NNTP server */
206 	ai = get_addrinfo(realhost, sport);
207 	if(ai == NULL) {
208 		free(realhost);
209 	}
210 	else {
211 		free(realhost);
212 		struct addrinfo * aii;
213 		print_phrases(msgs, both_phrases[3], ai->ai_canonname, NULL);
214 		for (aii=ai; aii; aii=aii->ai_next) {
215 			if (getnameinfo(aii->ai_addr, aii->ai_addrlen, name, namelen, NULL, 0, NI_NUMERICHOST) < 0) {
216 				name[0] = '\0';
217 			}
218 			/* Create a socket */
219 			if((sockfd = socket(aii->ai_family, aii->ai_socktype, aii->ai_protocol)) == -1) {
220 				continue; // MyPerror(both_phrases[6]);
221 			}
222 			else {
223 				/* Establish a connection */
224 				if(connect(sockfd, aii->ai_addr, aii->ai_addrlen ) == -1) {
225 					//MyPerror(both_phrases[7]);
226 					close(sockfd);
227 					sockfd = -1;
228 					continue;
229 				}
230 				else {
231 					int st = getnameinfo(aii->ai_addr, aii->ai_addrlen, name, namelen,
232 						NULL, 0, NI_NUMERICHOST);
233 					print_phrases(msgs, both_phrases[8],st == 0 ? name : host, NULL);
234 					if (st != 0) name[0] = '\0';
235 					break;
236 				}
237 			}
238 		}
239 		freeaddrinfo(ai);
240 		if (sockfd < 0) {
241 			MyPerror(both_phrases[6]); // or 7?
242 		}
243 #ifdef HAVE_LIBSSL
244 		if(sockfd > -1 && do_ssl == TRUE) {
245 			if((ssl_struct = SSL_new(test1)) == NULL) {
246 				error_log(ERRLOG_REPORT, both_phrases[18], NULL);
247 				close(sockfd);
248 				sockfd = -1;
249 			}
250 			else if(SSL_set_fd(ssl_struct, sockfd) == FALSE) {
251 				error_log(ERRLOG_REPORT, both_phrases[18], NULL);
252 				close(sockfd);
253 				sockfd = -1;
254 			}
255 			else if(SSL_connect(ssl_struct) != 1) {
256 				error_log(ERRLOG_REPORT, both_phrases[18], NULL);
257 				close(sockfd);
258 				sockfd = -1;
259 			}
260 			else {
261 				*ssl = ssl_struct;
262 			}
263 
264 		}
265 #endif
266 	}
267 	return sockfd;
268 }
269 /*---------------------------------------------------------------*/
disconnect_from_nntphost(int fd,int do_ssl,void ** ssl)270 void disconnect_from_nntphost(int fd, int do_ssl, void **ssl) {
271 #ifdef HAVE_LIBSSL
272 	if(do_ssl == TRUE) {
273 		fd = SSL_get_fd(*ssl);
274 		SSL_shutdown(*ssl);
275 		SSL_free(*ssl);
276 		*ssl = NULL;
277 	}
278 #endif
279 	close(fd);
280 
281 }
282 /*----------------------------------------------------------------*/
sputline(int fd,const char * outbuf,int do_ssl,void * ssl_buf)283 int sputline(int fd, const char *outbuf, int do_ssl, void *ssl_buf) {
284 
285 #ifdef DEBUG1
286 	do_debug("\nSENT: %s", outbuf);
287 #endif
288 #ifdef HAVE_LIBSSL
289 	if(do_ssl == TRUE) {
290 		if(fd == SSL_get_fd((SSL *)ssl_buf)) {
291 			return SSL_write((SSL *)ssl_buf, outbuf, strlen(outbuf));
292 		}
293 		else {
294 			return -1;
295 		}
296 	}
297 #endif
298 	return send(fd, outbuf, strlen(outbuf), 0);
299 
300 }
301 /*-------------------------------------------------------------*/
do_debug(const char * fmt,...)302 void do_debug(const char *fmt, ...) {
303 
304 	FILE *fptr = NULL;
305 	va_list args;
306 
307 	if((fptr = fopen(N_DEBUG, "a")) == NULL) {
308 		fptr = stderr;
309 	}
310 
311 	va_start(args, fmt);
312 	vfprintf(fptr, fmt, args);
313 	va_end(args);
314 
315 	if(fptr != stderr) {
316 		fclose(fptr);
317 	}
318 }
319 /*------------------------------------------------------------*/
do_debug_binary(int len,const char * str)320 void do_debug_binary(int len, const char *str) {
321 
322 	FILE *fptr = NULL;
323 
324 	if((fptr = fopen(N_DEBUG, "a")) == NULL) {
325 		fptr = stderr;
326 	}
327 	fwrite(str, sizeof(str[0]), len, fptr);
328 	if(fptr != stderr) {
329 		fclose(fptr);
330 	}
331 }
332 /*-----------------------------------------------------------*/
do_debug_vl(const char * fmt,va_list args)333 void do_debug_vl(const char *fmt, va_list args) {
334 	FILE *fptr = NULL;
335 
336 	if((fptr = fopen(N_DEBUG, "a")) == NULL) {
337 		fptr = stderr;
338 	}
339 	vprint_phrases(fptr, fmt, args);
340 
341 	if(fptr != stderr) {
342 		fclose(fptr);
343 	}
344 }
345 
346 /*------------------------------------------------------------*/
MyPerror(const char * message)347 void MyPerror(const char *message) {
348 
349 	/* can't just use perror, since it goes to stderr */
350 	/* and I need to route it to my errlog */
351 	/* so I have to recreate perror's format */
352 
353 	/* in case of NULL ptr */
354 
355 	if(message == NULL) {
356 		message="";
357 	}
358 #ifdef HAVE_STRERROR
359 	error_log(ERRLOG_REPORT, "%v1%: %v2%\n", message, strerror(errno), NULL);
360 #else
361 	error_log(ERRLOG_REPORT, both_phrases[9], message, errno, NULL);
362 #endif
363 }
364 /*-----------------------------------------------------------*/
findnl(char * startbuf,char * endbuf)365 char *findnl(char *startbuf, char *endbuf) {
366 	/* find a \r\n combo in the buffer */
367 
368 	for(; startbuf < endbuf ; startbuf++) {
369 		if(*startbuf == '\r') {
370 			if(*(startbuf+1) == '\n' && (startbuf < endbuf-1)) {
371 				return startbuf;
372 			}
373 		}
374 	}
375 	return NULL;
376 }
377 /*-----------------------------------------------------------*/
sgetline(int fd,char ** inbuf,int do_ssl,void * ssl_buf)378 int sgetline(int fd, char **inbuf, int do_ssl, void *ssl_buf) {
379 
380 	static char buf[MAXLINLEN+MAXLINLEN+6];
381 	static char *start = buf;
382 	static char *eob = buf;		/* end of buffer */
383 	int ret, i, len;
384 	char *ptr;
385 
386 #ifdef TIMEOUT
387 	fd_set myset;
388 	struct timeval mytimes;
389 #endif
390 	ret = 0;
391 	ptr = NULL;
392 
393 	if(fd < 0) {
394 		ret = -1;
395 	}
396 	else if(eob == start || (ptr = findnl(start, eob)) == NULL) {
397 
398 		/* TEST for not a full line in buffer */
399 		/* the eob == start test is needed in case the buffer is */
400 		/* empty, since we don't know what is in it. */
401 
402 		len = eob-start; 	/* length of partial line in buf */
403 		if((eob - buf) > MAXLINLEN) {
404 #ifdef DEBUG1
405 			do_debug("SHIFTING BUFFER\n");
406 #endif
407 			/* not enuf room in buffer for a full recv */
408 			memmove(buf, start, len);		/* move to start of buf */
409 			eob = buf + len;
410 			*eob = '\0';
411 			start = buf;			/* reset pointers */
412 		}
413 		/* try to get a line in, up to maxlen */
414 		do {
415 #ifdef DEBUG1
416 			do_debug("\nCURRENT BUF start = %d, end = %d, len = %d\n", start - buf, eob - buf, len);
417 #endif
418 #ifdef TIMEOUT
419 			/* handle timeout value */
420 			FD_ZERO(&myset);
421 			FD_SET(fd, &myset);
422 			mytimes.tv_sec = TimeOut;
423 			mytimes.tv_usec = 0;
424 
425 #ifdef MYSIGNAL
426 			signal_block(MYSIGNAL_BLOCK);
427 			/* block so we can't get interrupted by our signal defined in config.h */
428 #endif
429 #ifdef HAVE_LIBSSL
430 			if(do_ssl == TRUE && fd == SSL_get_fd((SSL *)ssl_buf) && SSL_pending((SSL *)ssl_buf)) {
431 				i = 1;
432 			}
433 			else {
434 #endif
435 			/* the fd+1 so we only scan our needed fd not all 1024 in set */
436 			i = select(fd+1, &myset, (fd_set *) NULL, (fd_set *) NULL, &mytimes);
437 #ifdef HAVE_LIBSSL
438 			}
439 #endif
440 			if(i>0) {
441 #ifdef HAVE_LIBSSL
442 #ifdef DEBUG1
443 				do_debug("SELECT got: %d\n", i);
444 #endif
445 				if(do_ssl == TRUE) {
446 					if(fd == SSL_get_fd((SSL *)ssl_buf)) {
447 						i = SSL_read((SSL *)ssl_buf, eob, MAXLINLEN-len);
448 					}
449 					else {
450 						i = -1;
451 					}
452 				}
453 				else
454 #endif
455 				i = recv(fd, eob, MAXLINLEN-len, 0);	/* get line */
456 			}
457 			else if(i == 0) {
458 				error_log(ERRLOG_REPORT, both_phrases[10], NULL);
459 			}      /* other errors will be handled down below */
460 #else
461 #ifdef HAVE_LIBSSL
462 			if(do_ssl == TRUE) {
463 				if(fd == SSL_get_fd((SSL *)ssl_buf)) {
464 					i = SSL_read((SSL *)ssl_buf, eob, MAXLINLEN-len);
465 				}
466 				else {
467 					i = -1;
468 				}
469 			}
470 			else
471 #endif
472 			i = recv(fd, eob, MAXLINLEN-len, 0);	/* get line */
473 #endif
474 
475 #ifdef MYSIGNAL
476 			signal_block(MYSIGNAL_UNBLOCK);
477 			/* we are done, now unblock it */
478 #endif
479 #ifdef DEBUG1
480 			do_debug("\nRECV returned %d", i);
481 			if ( i > 0) {
482 				do_debug("\nGOT: ");
483 				do_debug_binary(i,eob);
484 				do_debug(":END GOT");
485 			}
486 
487 #endif
488 
489 			if(i < 1) {
490 				if(i == 0) {
491 					/* No data read in either from recv or select timed out*/
492 					error_log(ERRLOG_REPORT, both_phrases[11], NULL);
493 				}
494 				else {
495 					MyPerror(both_phrases[12]);
496 				}
497 				ret = -1;
498 			}
499 			else {
500 
501 				eob += i;	/* increment buffer end */
502 				*eob = '\0';	/* NULL terminate it  */
503 
504 				len += i;
505 				ptr = findnl(start, eob);
506 			}
507 		} while(ptr == NULL && len < MAXLINLEN && ret == 0);
508 	}
509 	if(ptr != NULL) {
510 		/* we have a full line left in buffer */
511 		*ptr++ = '\n';	/* change \r\n to just \n */
512 		*ptr++ = '\0';	/* null terminate */
513 		*inbuf = start;
514 		ret = (ptr-1) - start;	/* length of string */
515 		start = ptr; 	/* skip \r\n */
516 	}
517 	else if(ret == 0) {
518 		/* partial line in buffer */
519 		/* null terminate */
520 		*eob = '\0';
521 		*inbuf = start;
522 		ret = (eob-1) - start;	/* length of string */
523 		start = ++eob;	/* point both past end */
524 	}
525 #ifdef DEBUG1
526 	if(ret > 0) {
527 		int flag = FALSE;
528 		char saveit = '\0';
529 		/* change nl to something we can see */
530 		if((*inbuf)[ret-1] == '\n') {
531 			flag = TRUE;
532 			(*inbuf)[ret-1] = '\\';
533 			(*inbuf)[ret] = 'n';
534 			saveit = (*inbuf)[ret+1];
535 			(*inbuf)[ret+1] = '\0';
536 		}
537 		do_debug("\nRETURNING len %d: %s\n", ret, *inbuf);
538 		/* put things back the way they were */
539 		if(flag == TRUE) {
540 			(*inbuf)[ret-1] = '\n';
541 			(*inbuf)[ret] = '\0';
542 			(*inbuf)[ret+1] = saveit;
543 		}
544 	}
545 	else {
546 		do_debug("\nRETURNING error, ret = %d", ret);
547 	}
548 #endif
549 	if(eob == start) {
550 		/* nothing left in buffer, reset pointers to start of buffer */
551 		/* to give us a full buffer to receive next data into */
552 		/* hopefully doing this will mean less buffer shifting */
553 		/* meaning faster receives */
554 		eob = start = buf;
555 #ifdef DEBUG1
556 		do_debug("EMPTY BUFFER, resetting to start\n");
557 		/* take this out when debugged */
558 		memset(buf, '\0', sizeof(buf));
559 #endif
560 	}
561 
562 	return ret;
563 }
564 /*----------------------------------------------------*/
565 #ifdef MYSIGNAL
signal_block(int action)566 void signal_block(int action) {
567 #ifdef HAVE_SIGACTION
568 	static sigset_t blockers;
569 	static int do_block = FALSE;
570 
571 	switch(action) {
572 		case MYSIGNAL_SETUP:	/* This must be called first */
573 			sigemptyset(&blockers);
574 			if(sigaddset(&blockers, MYSIGNAL) == -1 || sigaddset(&blockers,PAUSESIGNAL) == -1) {
575 				MyPerror(both_phrases[13]);
576 			}
577 			else {
578 				do_block = TRUE;
579 			}
580 			break;
581 		case MYSIGNAL_ADDPIPE:	/* add SIGPIPE for killprg.c */
582 			if(sigaddset(&blockers, SIGPIPE) == -1) {
583 				MyPerror(both_phrases[14]);
584 			}
585 			break;
586 		case MYSIGNAL_BLOCK:
587 			if(do_block == TRUE) {
588 				if(sigprocmask(SIG_BLOCK, &blockers, NULL) == -1) {
589 					MyPerror(both_phrases[13]);
590 				}
591 			}
592 			break;
593 		case MYSIGNAL_UNBLOCK:
594 			if(do_block == TRUE) {
595 				if(sigprocmask(SIG_UNBLOCK, &blockers, NULL) == -1) {
596 					MyPerror("Unable to unblock signal");
597 				}
598 			}
599 			break;
600 	}
601 #endif /* HAVE_SIGACTION */
602 }
603 #endif /* MYSIGNAL */
604 /*-------------------------------------------------------------------*/
error_log(int mode,const char * fmt,...)605 void error_log(int mode, const char *fmt, ...) {
606 
607 	/* if we have been passed a file, report all errors to that file */
608 	/* else report all errors to stderr */
609 	/* handle printf type formats, hence the varargs stuff */
610 
611 	FILE *fptr = NULL;
612 	va_list args;
613 	static char errfile[PATH_MAX] = { '\0' };
614 	static int debug = FALSE;
615 
616 	va_start(args, fmt);	/* set up args */
617 
618 	switch(mode) {
619 	  case ERRLOG_SET_DEBUG:
620 		debug = TRUE;
621 		break;
622 	  case ERRLOG_SET_FILE:
623 		strcpy(errfile,fmt);
624 		break;
625 	  case ERRLOG_SET_STDERR:
626 		errfile[0] = '\0';
627 		break;
628 	  case ERRLOG_REPORT:
629 		if(errfile[0] == '\0' || (fptr = fopen(errfile, "a")) == NULL) {
630 			fptr = stderr;
631 		}
632 		vprint_phrases(fptr, fmt, args);
633 		if(debug == TRUE) {
634 			va_list args;
635 			va_start(args, fmt);
636 			do_debug_vl(fmt, args);
637 			va_end(args);
638 		}
639 		if(fptr != stderr) {
640 			fclose(fptr);
641 		}
642 		break;
643 	}
644 	va_end(args);		/* so we can return normally */
645 	return;
646 }
647 /*--------------------------------------------------------------------------*/
build_args(const char * fname,int * nrargs)648 char **build_args(const char *fname, int *nrargs) {
649 	/* read a file and parse the args into an argv array */
650 	/* make two passes thru the file, 1st count them so can allocate array */
651 	/* then allocate each one individually */
652 
653 	char **args = NULL;
654 	char linein[MAXLINLEN+1];
655 	int x, len, done, counter, argc = 0;
656 	FILE *fpi;
657 
658 	if((fpi = fopen(fname, "r")) == NULL) {
659 		MyPerror(fname);
660 	}
661 	else {
662 		/* first pass, just count em */
663 		counter = 0;
664 		while(fgets(linein, MAXLINLEN, fpi) != NULL) {
665 			x = 0;
666 			done = FALSE;
667 			while(linein[x] != '\0' && done == FALSE) {
668 				while(isspace(linein[x])) {
669 					x++;		/* skip white space */
670 				}
671 				if(linein[x] == FILE_ARG_COMMENT || linein[x] == '\0') {
672 					done = TRUE;	/* skip rest of line */
673 				}
674 				else {
675 					counter++;	/* another arg */
676 					while(!isspace(linein[x]) && linein[x] != '\0') {
677 						x++;	/* skip rest of arg */
678 					}
679 				}
680 			}
681 		}
682 #ifdef DEBUG1
683 		do_debug("Counted %d args in %s\n", counter, fname);
684 #endif
685 		if((args = calloc( counter, sizeof(char *))) == NULL) {
686 			error_log(ERRLOG_REPORT, both_phrases[15], fname, NULL);
687 		}
688 		else {
689 			/* pass two  read em and alloc em*/
690 			fseek(fpi, 0L, SEEK_SET);	/* rewind the file for pass two */
691 			counter = 0;	/* start at 0 again */
692 			while(fgets(linein, MAXLINLEN, fpi) != NULL) {
693 				x = 0;
694 				done = FALSE;
695 				while(linein[x] != '\0' && done == FALSE) {
696 					while(isspace(linein[x])) {
697 						x++;		/* skip white space */
698 					}
699 					if(linein[x] == FILE_ARG_COMMENT || linein[x] == '\0') {
700 						done = TRUE;	/* skip rest of line */
701 					}
702 					else {
703 						/* have another arg */
704 						len = 1;
705 						while(!isspace(linein[x+len]) && linein[x+len] != '\0') {
706 							len++;	/* find length of arg */
707 						}
708 						if((args[counter] = calloc( len+1, sizeof(char))) == NULL) {
709 							error_log(ERRLOG_REPORT, both_phrases[16], NULL);
710 						}
711 						else {
712 							strncpy(args[counter], &linein[x], len);
713 							args[counter][len] = '\0';	/* ensure null termination */
714 #ifdef DEBUG1
715 							do_debug("Read arg #%d: '%s'\n", counter, args[counter]);
716 #endif
717 							counter++;
718 						}
719 						x += len;	/* go onto next one */
720 					}
721 				}
722 			}
723 			argc = counter;		/* total nr of args read in and alloced */
724 		}
725 		fclose(fpi);
726 	}
727 
728 	*nrargs = argc;
729 	return args;
730 }
731 /*-----------------------------------------------------------------------------*/
732 /* free the memory allocated in build_args() */
free_args(int argc,char * argv[])733 void free_args(int argc, char *argv[]) {
734 
735 	int i;
736 	for(i=0;i<argc;i++) {
737 		free(argv[i]);
738 	}
739 	free(argv);
740 }
741 /*--------------------------------------------------------------------------------*/
742 /* These are used by the load_phrases() stuff					  */
743 /* read_array() and do_a_phrase() don't use the stored phrases                    */
744 /* since they are used when the phrases are being loaded. 			  */
745 /*--------------------------------------------------------------------------------*/
read_array(FILE * fpi,int nr,int save_yn)746 char **read_array(FILE *fpi, int nr, int save_yn) {
747 
748 	int i, retval = 0;
749 	char **array = NULL;
750 	char linein[MAXLINLEN+1];
751 
752 	if(save_yn == TRUE && (array = calloc( nr, sizeof(char *))) == NULL) {
753 		error_log(ERRLOG_REPORT, "Out of memory reading phrases\n", NULL);
754 	}
755 	else {
756 		for(i=0;retval == 0 && i < nr; i++) {
757 			if(fgets(linein, MAXLINLEN, fpi) != NULL) {
758 				if(save_yn == TRUE) {
759 					if((array[i] = do_a_phrase(linein)) == NULL) {
760 						retval = -1;
761 					}
762 				}
763 			}
764 		}
765 	}
766 
767 	if(retval == -1) {
768 		free_array(nr, array);
769 		array = NULL;
770 	}
771 	return array;
772 }
773 /*-------------------------------------------------------------------------------*/
free_array(int n,char ** arr)774 void free_array(int n, char **arr) {
775 	int i;
776 	if(arr != NULL) {
777 		for(i=0;i<n;i++) {
778 			if(arr[i] != NULL) {
779 				free(arr[i]);
780 			}
781 		}
782 		free(arr);
783 	}
784 }
785 /*--------------------------------------------------------------------------------*/
do_a_phrase(char linein[])786 char *do_a_phrase(char linein[]) {
787 
788 	char *lineout;
789 	int i, stt, end;
790 	static char default_phrase[] = "";
791 
792 
793 	i = strlen(linein);
794 	lineout = NULL;
795 
796 	/* find start and finish of string */
797 	for(stt = 0; stt != i && linein[stt] != '"'; stt++) {
798 	}
799 	for(end = i-1;  i!= 0 && linein[end] != '"'; end--) {
800 	}
801 	if(end <= stt) {
802 		error_log(ERRLOG_REPORT, "Invalid line, %v1%, Ignoring\n", linein, NULL);
803 		lineout = default_phrase;
804 	}
805 	else {
806 		i = end - stt;
807 		if((lineout = calloc(i, sizeof(char))) == NULL) {
808 			error_log(ERRLOG_REPORT, "Out of Memory Reading Phrases\n", NULL);
809 		}
810 		else {
811 			strncpy(lineout, &linein[stt+1], i-1);	/* put the string into place */
812 			lineout[i-1] = '\0';			/* null terminate it */
813 #ifdef DEBUG1
814 			do_debug("Got phrase:%s:\n", lineout);
815 #endif
816 			convert_nl(lineout);
817 		}
818 	}
819 	return lineout;
820 }
821 /*-----------------------------------------------------------------------------------*/
convert_nl(char * linein)822 void convert_nl(char *linein) {
823 	/* go thru a string, and convert \r \t \n (2 chars) to actual control codes */
824 	char c;
825 	int i, x, len;
826 
827 	if(linein != NULL) {
828 		len = strlen(linein);
829 		for(i = 0; i < len ; i++ ) {
830 			if(linein[i] == '\\') {
831 				c = linein[i+1];
832 				if(c == 'r' || c == 'n' || c == 't') {
833 					switch(c) {
834 					  case 'r':
835 						c = '\r';
836 						break;
837 					  case 'n':
838 						c = '\n';
839 						break;
840 					  case 't':
841 						c = '\t';
842 						break;
843 					}
844 					linein[i] = c;
845 					for ( x = i + 1; x < len ; x++ ) {
846 						linein[x] = linein[x+1];
847 					}
848 					len--;
849 				}
850 			}
851 		}
852 	}
853 }
854 /*-----------------------------------------------------------------------------------*/
print_phrases(FILE * fpout,const char * argstr,...)855 void print_phrases(FILE *fpout, const char *argstr, ... ){
856 
857 	va_list vargs;
858 
859 	va_start(vargs, argstr);
860 
861 	if(fpout != NULL) {
862 		/* if NULL don't need to print anything */
863 		vprint_phrases(fpout, argstr, vargs);
864 	}
865 
866 	va_end(vargs);
867 }
868 
869 /*-----------------------------------------------------------------------------------*/
vprint_phrases(FILE * fpout,const char * argstr,va_list vargs)870 void vprint_phrases(FILE *fpout, const char *argstr, va_list vargs) {
871 	/* this routine takes in argstr, parses it for args and prints everything */
872 	/* out, the args may not be in order ("hi %v2% there %v1% guys")	  */
873 	/* args are %v#%.  The varargs are all char ptrs */
874 
875 	const char *ptr, *pnumber;
876 	char *tptr, block[PHRASES_BLOCK_SIZE+1], *in[PHRASES_MAX_NR_VARS];
877 	int len, varyn, vnr, nrvars;
878 
879 	/* create an array with our string pointers */
880 	nrvars = 0;
881 	tptr = va_arg(vargs, char *);
882 	while(tptr != NULL && nrvars < PHRASES_MAX_NR_VARS) {
883 		in[nrvars++] = tptr;
884 		tptr = va_arg(vargs, char *);
885 	}
886 
887 	varyn = FALSE;
888 	ptr = argstr;
889 	if(ptr != NULL) {
890 		while( *ptr != '\0' ) {
891 			len = 0;
892 			while(len < PHRASES_BLOCK_SIZE && *ptr != '\0') {
893 				if(*ptr == PHRASES_SEPARATOR && *(ptr+1) == PHRASES_VAR_CHAR) {
894 					pnumber = ptr+2;
895 					while(isdigit(*pnumber)) {
896 						pnumber++;
897 					}
898 					if(pnumber != ptr+2 && *pnumber == PHRASES_SEPARATOR) {
899 						/* bingo, we match syntax %v1% handle the variables */
900 						sscanf(ptr+2, "%d", &vnr);	/* get the number */
901 						/* now print it */
902 						if(vnr <= nrvars) {
903 							varyn = TRUE;
904 							/* first, print what's currently in the buffer */
905 							block[len] = '\0';
906 							fputs(block,fpout);
907 							len = 0;
908 							/* now print the variable */
909 							/* -1 cause array starts at 0 vars at 1 */
910 							fputs(in[vnr-1], fpout);
911 							ptr = pnumber+1;	/* advance past var */
912 						}
913 					}
914 				}
915 				if(varyn == FALSE) {
916 					block[len++] = *ptr++;
917 				}
918 				else {
919 					varyn = FALSE;		/* reset it */
920 				}
921 			}
922 			if(len > 0 ) {
923 				block[len] = '\0';	/* null terminate string */
924 				fputs(block, fpout);
925 			}
926 		}
927 	}
928 }
929 /*----------------------------------------------------------*/
str_int(int nrin)930 char *str_int(int nrin) {
931 
932 	static char strings[PHRASES_MAX_NR_VARS][12];	/* lets pray ints don't get bigger than this */
933 	static int which = 0;
934 
935 	/* use a set of rotating buffers so can make multiple str_int calls */
936 	if(++which == PHRASES_MAX_NR_VARS) {
937 		which = 0;
938 	}
939 
940 	sprintf(strings[which], "%d", nrin);
941 
942 	return strings[which];
943 }
944 /*----------------------------------------------------------*/
str_long(long nrin)945 char *str_long(long nrin) {
946 
947 	static char strings[PHRASES_MAX_NR_VARS][20];	/* lets pray longs don't get bigger than this */
948 	static int which = 0;
949 
950 	/* use a set of rotating buffers so can make multiple str_int calls */
951 	if(++which == PHRASES_MAX_NR_VARS) {
952 		which = 0;
953 	}
954 
955 	sprintf(strings[which], "%ld", nrin);
956 
957 	return strings[which];
958 }
959 /*-----------------------------------------------------------*/
960 /* print NULL or the string */
null_str(const char * ptr)961 const char *null_str(const char *ptr) {
962         const char *nullp = "NULL";
963 
964         return (ptr == NULL) ? nullp : ptr;
965 }
966 /*-----------------------------------------------------------*/
967 /* print TRUE or FALSE if our nr is 0 or non-zero */
true_str(int nr)968 const char *true_str(int nr) {
969         const char *true_s = "TRUE";
970         const char *false_s = "FALSE";
971 
972         return (nr == TRUE) ? true_s : false_s;
973 }
974