1 #include <config.h>
2
3 #include <stdlib.h>
4 #include <stdio.h>
5
6 #ifdef HAVE_UNISTD_H
7 #include <unistd.h>
8 #endif
9
10 #ifdef HAVE_SYS_WAIT_H
11 #include <sys/wait.h>
12 #endif
13
14 #include <string.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17
18 #ifdef HAVE_DIRENT_H
19 # include <dirent.h>
20 #else
21 # ifdef HAVE_SYS_NDIR_H
22 # include <sys/ndir.h>
23 # endif
24 # ifdef HAVE_SYS_DIR_H
25 # include <sys/dir.h>
26 # endif
27 #endif
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 "batch.h"
37 #include "suckutils.h"
38 #include "phrases.h"
39 #include "active.h"
40 #include "timer.h"
41
42 /*--------------------------------------------------------*/
43 /* function prototypes */
44 int post_one_msg(PMaster, int, char *);
45
46 /*----------------------------------------------------------*/
do_innbatch(PMaster master)47 int do_innbatch(PMaster master) {
48 /* build batch file that contains article listing */
49 /* needed by innxmit */
50 /* this is done by searching thru MSGDIR to find files */
51 /* which match our naming convention */
52
53 int i, retval = RETVAL_OK;
54 FILE *fptr;
55 const char *tmp;
56 DIR *dptr;
57 struct dirent *entry;
58
59 print_phrases(master->msgs, batch_phrases[3], NULL);
60
61 if((fptr = fopen(master->batchfile, "w")) == NULL) {
62 MyPerror(master->batchfile);
63 retval = RETVAL_ERROR;
64 }
65 else if((dptr = opendir(full_path(FP_GET, FP_MSGDIR, ""))) == NULL) {
66 MyPerror(full_path(FP_GET, FP_MSGDIR, ""));
67 retval = RETVAL_ERROR;
68 fclose(fptr);
69 }
70 else {
71 tmp = full_path(FP_GET_POSTFIX, 0, ""); /* this will be string we search for */
72 /* look for entries which have our postfix */
73 while((entry = readdir(dptr)) != NULL && retval == RETVAL_OK) {
74 /* ignore hidden files */
75 if(entry->d_name[0] != '.' && strstr(entry->d_name, tmp) != NULL) {
76 i = fprintf(fptr, "%s\n", full_path(FP_GET_NOPOSTFIX, FP_MSGDIR, entry->d_name));
77 if(i <= 0) {
78 retval = RETVAL_ERROR;
79 MyPerror(master->batchfile);
80 }
81 }
82 }
83 fclose(fptr);
84 closedir(dptr);
85 }
86 return retval;
87 }
88 /*----------------------------------------------------------*/
do_rnewsbatch(PMaster master)89 int do_rnewsbatch(PMaster master) {
90
91 /* build rnews formated file of articles */
92 /* this is done by searching thru MSGDIR to find files */
93 /* which match our naming convention */
94
95 /* if max_file_size > 0, then create multiple files up to max file size */
96
97 int i, x, batchnr = 0, retval = RETVAL_OK;
98 FILE *fptr = NULL, *fpin;
99 const char *tptr, *tmp;
100 char buf[MAXLINLEN];
101 DIR *dptr;
102 struct dirent *entry;
103 struct stat sbuf, tbuf;
104 long cursize = 0L;
105
106 print_phrases(master->msgs, batch_phrases[4], NULL);
107
108 if((dptr = opendir(full_path(FP_GET, FP_MSGDIR, ""))) == NULL) {
109 MyPerror(full_path(FP_GET, FP_MSGDIR, ""));
110 retval = RETVAL_ERROR;
111 }
112 else {
113 tmp = full_path(FP_GET_POSTFIX, 0, ""); /* this will be string we search for */
114 /* look for entries which have our postfix */
115 while(retval == RETVAL_OK && (entry = readdir(dptr))) {
116 /* ignore hidden files */
117 if(entry->d_name[0] != '.' && strstr(entry->d_name, tmp) != NULL) {
118 tptr = full_path(FP_GET_NOPOSTFIX, FP_MSGDIR, entry->d_name);
119 if(stat(tptr, &sbuf) != 0 || (fpin = fopen(tptr, "r")) == NULL) {
120 MyPerror(tptr);
121 retval = RETVAL_ERROR;
122 }
123 else {
124 if( cursize == 0 ) {
125 if(fptr != NULL) {
126 /* close old file */
127 fclose(fptr);
128 batchnr++;
129 }
130 /* have to open file */
131 if(batchnr == 0) {
132 strcpy(buf, master->batchfile);
133 }
134 else {
135 sprintf(buf, "%s%d", master->batchfile, batchnr);
136 }
137 if(master->debug == TRUE) {
138 do_debug("BATCH FILE: %s\n", buf);
139 }
140 if(stat(buf, &tbuf) == 0) {
141 /* whoops file already exists */
142 MyPerror(buf);
143 retval = RETVAL_ERROR;
144 }
145 else if((fptr = fopen(buf, "w")) == NULL) {
146 MyPerror(buf);
147 retval = RETVAL_ERROR;
148 }
149 }
150 if(retval == RETVAL_OK) {
151 /* first put #! rnews size */
152 fprintf(fptr, "#! rnews %ld\n", (long) sbuf.st_size);
153 /* use fread/fwrite in case lines are longer than MAXLINLEN */
154 while((i = fread(buf, 1, MAXLINLEN, fpin)) > 0 && retval == RETVAL_OK) {
155 x = fwrite(buf, 1, i, fptr);
156 if(x != i) {
157 /* error writing file */
158 retval = RETVAL_ERROR;
159 MyPerror(buf);
160 }
161 }
162 if(retval == RETVAL_OK ) {
163 unlink(tptr); /* we are done with it, nuke it */
164 cursize += sbuf.st_size;
165 /* keep track of current file size, we can ignore the #! rnews */
166 /* size, since it adds so little to the overall size */
167
168 if(master->rnews_size > 0L && cursize > master->rnews_size) {
169 /* reached file size length */
170 cursize = 0L; /* this will force a close and open on next article */
171 }
172 }
173 }
174 fclose(fpin);
175 }
176 }
177 }
178 if(fptr != NULL) {
179 fclose(fptr);
180 }
181
182 closedir(dptr);
183 }
184 return retval;
185 }
186 /*----------------------------------------------------------------------------------*/
do_lmovebatch(PMaster master)187 void do_lmovebatch(PMaster master) {
188 /* fork lmove */
189 const char *args[LMOVE_MAX_ARGS];
190 int i, x;
191 pid_t pid;
192
193 print_phrases(master->msgs, batch_phrases[0], NULL);
194
195 /* first build command */
196 args[0] = "lmove";
197 args[1] = "-c";
198 args[2] = master->batchfile;
199 args[3] = "-d";
200 args[4] = full_path(FP_GET, FP_MSGDIR, "");
201 i = 5;
202 if(master->errlog != NULL) {
203 args[i++ ] = "-E";
204 args[i++ ] = master->errlog;
205 }
206 if(master->phrases != NULL) {
207 args[i++] = "-l";
208 args[i++] = master->phrases;
209 }
210
211 if(master->debug == TRUE) {
212 args[i++] = "-D";
213 }
214 args[i] = NULL;
215
216 if(master->debug == TRUE) {
217 do_debug("Calling lmove with args:");
218 for(x = 0; x < i; x++) {
219 do_debug(" %s", args[x]);
220 }
221 do_debug("\n");
222 }
223
224 /* now fork and execl */
225 pid = fork();
226 if(pid == 0) {
227 /* in child */
228 execvp(args[0], (char *const *) args);
229 MyPerror(batch_phrases[2]); /* only get here on errors */
230 exit(-1); /* so we aren't running two sucks */
231 }
232 else if(pid < 0) {
233 /* whoops */
234 MyPerror(batch_phrases[1]);
235 }
236 else {
237 /* in parent let the child finish */
238 wait(NULL);
239 }
240 }
241 /*---------------------------------------------------------------------------*/
do_localpost(PMaster master)242 int do_localpost(PMaster master) {
243
244 /* post articles to local server using IHAVE */
245 int sockfd, count = 0, retval = RETVAL_OK;
246 FILE *fp_list;
247 char msg[MAXLINLEN+1];
248 const char *fname;
249
250 TimerFunc(TIMER_START, 0, NULL);
251
252 print_phrases(master->msgs, batch_phrases[5], master->localhost, NULL);
253
254 if(master->batchfile == NULL) {
255 error_log(ERRLOG_REPORT, batch_phrases[6], NULL);
256 retval = RETVAL_ERROR;
257 }
258 else {
259 fname = full_path(FP_GET, FP_TMPDIR, master->batchfile);
260 if((fp_list = fopen(fname, "r")) == NULL ) {
261 MyPerror(fname);
262 retval = RETVAL_ERROR;
263 }
264 else {
265 if((sockfd = connect_local(master)) < 0) {
266 retval = RETVAL_ERROR;
267 }
268 else {
269 while(retval == RETVAL_OK && fgets(msg, MAXLINLEN, fp_list) != NULL) {
270 retval = post_one_msg(master, sockfd, msg);
271 if(retval == RETVAL_OK) {
272 count++;
273 }
274 }
275 disconnect_from_nntphost(sockfd, master->local_ssl, &master->local_ssl_struct);
276 }
277 fclose(fp_list);
278 }
279 if(retval == RETVAL_OK) {
280 if(master->debug == TRUE) {
281 do_debug("deleting %s\n", fname);
282 }
283 unlink(fname);
284 }
285 }
286
287 print_phrases(master->msgs, batch_phrases[10], str_int(count), NULL);
288 TimerFunc(TIMER_TIMEONLY, 0,master->msgs);
289
290 return retval;
291
292 }
293 /*------------------------------------------------------------------------------------------------*/
post_one_msg(PMaster master,int sockfd,char * msg)294 int post_one_msg(PMaster master, int sockfd, char *msg) {
295
296 int len, nr, longline, do_unlink = FALSE, retval = RETVAL_OK;
297 char *msgid, *resp, linein[MAXLINLEN+4]; /* the extra in case of . in first pos */
298 FILE *fpi;
299
300 /* msg contains the path and msgid */
301 msgid = strstr(msg, " <"); /* find the start of the msgid */
302 if(msgid == NULL) {
303 error_log(ERRLOG_REPORT, batch_phrases[7], msg, NULL);
304 }
305 else {
306 *msgid = '\0'; /* end the path name */
307 msgid++; /* so we point to the < */
308
309 len = strlen(msgid);
310 /* strip a nl */
311 if(msgid[len-1] == '\n') {
312 msgid[len-1] = '\0';
313 }
314 if(master->debug == TRUE) {
315 do_debug("File Name = \"%s\"\n", msg);
316 }
317
318 if((fpi = fopen(msg, "r")) == NULL) {
319 MyPerror(msg);
320 }
321 else {
322 sprintf(linein, "IHAVE %s\r\n", msgid);
323 if(master->debug == TRUE) {
324 do_debug("sending command %s", linein);
325 }
326 sputline(sockfd, linein, master->local_ssl, master->local_ssl_struct);
327 if(sgetline(sockfd, &resp, master->local_ssl, master->local_ssl_struct) < 0) {
328 retval = RETVAL_ERROR;
329 }
330 else {
331 if(master->debug == TRUE) {
332 do_debug("got answer: %s", resp);
333 }
334 number(resp, &nr);
335 /* added for prob */
336 if(master->debug == TRUE) {
337 do_debug("Answer=%d\n", nr);
338 }
339 if(nr == 435) {
340 error_log(ERRLOG_REPORT, batch_phrases[11], msgid, resp, NULL);
341 do_unlink = TRUE;
342 }
343 else if(nr != 335) {
344 error_log(ERRLOG_REPORT, batch_phrases[8], msgid, resp, NULL);
345 }
346 else {
347 /* send the article */
348 longline = FALSE;
349 while(fgets(linein, MAXLINLEN, fpi) != NULL) {
350 /* added for prob */
351 if(master->debug == TRUE) {
352 do_debug("sending line-%s--\n", linein);
353 }
354
355 len = strlen(linein);
356 if(longline == FALSE && linein[0] == '.') {
357 /* double the . at beginning of line */
358 memmove(linein+1,linein,++len);
359 linein[0] = '.';
360 }
361
362 longline = ( linein[len - 1] == '\n' ) ? FALSE : TRUE ;
363 if(longline == FALSE) {
364 /* replace nl with cr nl */
365 strcpy(&linein[len-1], "\r\n");
366 }
367 sputline(sockfd, linein, master->local_ssl, master->local_ssl_struct);
368 }
369 if(longline == TRUE) {
370 /* end the last line */
371 sputline(sockfd, "\r\n", master->local_ssl, master->local_ssl_struct);
372 }
373 /* end the article */
374 sputline(sockfd, ".\r\n", master->local_ssl, master->local_ssl_struct);
375 /* put in for prob */
376 if(master->debug == TRUE) {
377 do_debug("Finished sending article\n");
378 }
379 if(sgetline(sockfd, &resp, master->local_ssl, master->local_ssl_struct) < 0 ) {
380 retval = RETVAL_ERROR;
381 }
382 else {
383 if(master->debug == TRUE) {
384 do_debug("Got response: %s", resp);
385 }
386 number(resp, &nr);
387 if(nr == 437) {
388 error_log(ERRLOG_REPORT, batch_phrases[12], msgid, resp, NULL);
389 do_unlink = TRUE;
390 }
391 else if(nr == 235) {
392 /* successfully posted, nuke it */
393 do_unlink = TRUE;
394 }
395 else {
396 error_log(ERRLOG_REPORT, batch_phrases[9], msgid, resp, NULL);
397 }
398 }
399 }
400 }
401 fclose(fpi);
402 if(do_unlink == TRUE) {
403 unlink(msg);
404 }
405
406 }
407 }
408
409 return retval;
410
411 }
412 /*--------------------------------------------------------------------------*/
do_post_filter(PMaster master)413 void do_post_filter(PMaster master) {
414 /* call lpost filter prgm with batchfile as argument */
415 const char *msgdir;
416 pid_t pid;
417
418 if(master->post_filter != NULL) {
419 msgdir = full_path(FP_GET, FP_MSGDIR, "");
420 if(master->debug == TRUE) {
421 do_debug("Running %s with %s as args\n", master->post_filter, msgdir);
422 }
423
424 pid = fork();
425 if(pid == 0) {
426 /* in child */
427 if(execlp(master->post_filter, master->post_filter, msgdir, NULL) == -1) {
428 /* big error */
429 MyPerror(master->post_filter);
430 exit(-1); /* so we aren't running two sucks */
431 }
432 }
433 else if(pid == -1) {
434 /* whoops */
435 MyPerror(master->post_filter);
436 }
437 else {
438 /* parent, wait on child */
439 wait(NULL);
440 }
441 }
442 }
443