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