1 /* rcstuff.c
2 */
3 /* This software is copyrighted as detailed in the LICENSE file. */
4
5
6 #include "EXTERN.h"
7 #include "common.h"
8 #include "list.h"
9 #include "util.h"
10 #include "util2.h"
11 #include "hash.h"
12 #include "cache.h"
13 #include "bits.h"
14 #include "ngdata.h"
15 #include "nntpclient.h"
16 #include "datasrc.h"
17 #include "nntp.h"
18 #include "term.h"
19 #include "final.h"
20 #include "trn.h"
21 #include "env.h"
22 #include "init.h"
23 #include "intrp.h"
24 #include "only.h"
25 #include "rcln.h"
26 #include "last.h"
27 #include "autosub.h"
28 #include "rt-select.h"
29 #include "rt-page.h"
30 #include "INTERN.h"
31 #include "rcstuff.h"
32 #include "rcstuff.ih"
33
34 static bool foundany;
35
36 bool
rcstuff_init()37 rcstuff_init()
38 {
39 MULTIRC* mptr = NULL;
40 int i;
41
42 multirc_list = new_list(0,0,sizeof(MULTIRC),20,LF_ZERO_MEM|LF_SPARSE,NULL);
43
44 if (trnaccess_mem) {
45 NEWSRC* rp;
46 char* s;
47 char* section;
48 char* cond;
49 char** vals = prep_ini_words(rcgroups_ini);
50 s = trnaccess_mem;
51 while ((s = next_ini_section(s,§ion,&cond)) != NULL) {
52 if (*cond && !check_ini_cond(cond))
53 continue;
54 if (strncaseNE(section, "group ", 6))
55 continue;
56 i = atoi(section+6);
57 if (i < 0)
58 i = 0;
59 s = parse_ini_section(s, rcgroups_ini);
60 if (!s)
61 break;
62 rp = new_newsrc(vals[RI_ID],vals[RI_NEWSRC],vals[RI_ADDGROUPS]);
63 if (rp) {
64 MULTIRC* mp;
65 NEWSRC* prev_rp;
66
67 mp = multirc_ptr(i);
68 prev_rp = mp->first;
69 if (!prev_rp)
70 mp->first = rp;
71 else {
72 while (prev_rp->next)
73 prev_rp = prev_rp->next;
74 prev_rp->next = rp;
75 }
76 mp->num = i;
77 if (!mptr)
78 mptr = mp;
79 /*rp->flags |= RF_USED;*/
80 }
81 /*else
82 ;$$complain?*/
83 }
84 free((char*)vals);
85 free(trnaccess_mem);
86 }
87
88 if (UseNewsrcSelector && !checkflag)
89 return TRUE;
90
91 foundany = FALSE;
92 if (mptr && !use_multirc(mptr))
93 use_next_multirc(mptr);
94 if (!multirc) {
95 mptr = multirc_ptr(0);
96 mptr->first = new_newsrc("default",NULL,NULL);
97 if (!use_multirc(mptr)) {
98 printf("Couldn't open any newsrc groups. Is your access file ok?\n");
99 finalize(1);
100 }
101 }
102 if (checkflag) /* were we just checking? */
103 finalize(foundany); /* tell them what we found */
104 return foundany;
105 }
106
107 NEWSRC*
new_newsrc(name,newsrc,add_ok)108 new_newsrc(name,newsrc,add_ok)
109 char* name;
110 char* newsrc;
111 char* add_ok;
112 {
113 char tmpbuf[CBUFLEN];
114 NEWSRC* rp;
115 DATASRC* dp;
116
117 if (!name || !*name)
118 return NULL;
119
120 if (!newsrc || !*newsrc) {
121 newsrc = getenv("NEWSRC");
122 if (!newsrc)
123 newsrc = RCNAME;
124 }
125
126 dp = get_datasrc(name);
127 if (!dp)
128 return NULL;
129
130 rp = (NEWSRC*)safemalloc(sizeof (NEWSRC));
131 bzero((char*)rp, sizeof (NEWSRC));
132 rp->datasrc = dp;
133 rp->name = savestr(filexp(newsrc));
134 sprintf(tmpbuf, RCNAME_OLD, rp->name);
135 rp->oldname = savestr(tmpbuf);
136 sprintf(tmpbuf, RCNAME_NEW, rp->name);
137 rp->newname = savestr(tmpbuf);
138
139 switch (add_ok? *add_ok : 'y') {
140 case 'n':
141 case 'N':
142 break;
143 default:
144 if (dp->flags & DF_ADD_OK)
145 rp->flags |= RF_ADD_NEWGROUPS;
146 /* FALL THROUGH */
147 case 'm':
148 case 'M':
149 rp->flags |= RF_ADD_GROUPS;
150 break;
151 }
152 return rp;
153 }
154
155 bool
use_multirc(mp)156 use_multirc(mp)
157 MULTIRC* mp;
158 {
159 NEWSRC* rp;
160 bool had_trouble = FALSE;
161 bool had_success = FALSE;
162
163 for (rp = mp->first; rp; rp = rp->next) {
164 if ((rp->datasrc->flags & DF_UNAVAILABLE) || !lock_newsrc(rp)
165 || !open_datasrc(rp->datasrc) || !open_newsrc(rp)) {
166 unlock_newsrc(rp);
167 had_trouble = TRUE;
168 }
169 else {
170 rp->datasrc->flags |= DF_ACTIVE;
171 rp->flags |= RF_ACTIVE;
172 had_success = TRUE;
173 }
174 }
175 if (had_trouble)
176 get_anything();
177 if (!had_success)
178 return FALSE;
179 multirc = mp;
180 #ifdef NO_FILELINKS
181 if (!write_newsrcs(multirc))
182 get_anything();
183 #endif
184 return TRUE;
185 }
186
187 void
unuse_multirc(mptr)188 unuse_multirc(mptr)
189 MULTIRC* mptr;
190 {
191 NEWSRC* rp;
192
193 if (!mptr)
194 return;
195
196 write_newsrcs(mptr);
197
198 for (rp = mptr->first; rp; rp = rp->next) {
199 unlock_newsrc(rp);
200 rp->flags &= ~RF_ACTIVE;
201 rp->datasrc->flags &= ~DF_ACTIVE;
202 }
203 if (ngdata_list) {
204 close_cache();
205 hashdestroy(newsrc_hash);
206 walk_list(ngdata_list, clear_ngitem, 0);
207 delete_list(ngdata_list);
208 ngdata_list = NULL;
209 first_ng = NULL;
210 last_ng = NULL;
211 ngptr = NULL;
212 current_ng = NULL;
213 recent_ng = NULL;
214 starthere = NULL;
215 sel_page_np = NULL;
216 }
217 ngdata_cnt = 0;
218 newsgroup_cnt = 0;
219 newsgroup_toread = 0;
220 multirc = NULL;
221 }
222
223 bool
use_next_multirc(mptr)224 use_next_multirc(mptr)
225 MULTIRC* mptr;
226 {
227 register MULTIRC* mp = multirc_ptr(mptr->num);
228
229 unuse_multirc(mptr);
230
231 for (;;) {
232 mp = multirc_next(mp);
233 if (!mp)
234 mp = multirc_low();
235 if (mp == mptr) {
236 use_multirc(mptr);
237 return FALSE;
238 }
239 if (use_multirc(mp))
240 break;
241 }
242 return TRUE;
243 }
244
245 bool
use_prev_multirc(mptr)246 use_prev_multirc(mptr)
247 MULTIRC* mptr;
248 {
249 register MULTIRC* mp = multirc_ptr(mptr->num);
250
251 unuse_multirc(mptr);
252
253 for (;;) {
254 mp = multirc_prev(mp);
255 if (!mp)
256 mp = multirc_high();
257 if (mp == mptr) {
258 use_multirc(mptr);
259 return FALSE;
260 }
261 if (use_multirc(mp))
262 break;
263 }
264 return TRUE;
265 }
266
267 char*
multirc_name(mp)268 multirc_name(mp)
269 register MULTIRC* mp;
270 {
271 char* cp;
272 if (mp->first->next)
273 return "<each-newsrc>";
274 if ((cp = rindex(mp->first->name, '/')) != NULL)
275 return cp+1;
276 return mp->first->name;
277 }
278
279 static bool
clear_ngitem(cp,arg)280 clear_ngitem(cp, arg)
281 char* cp;
282 int arg;
283 {
284 NGDATA* ncp = (NGDATA*)cp;
285
286 if (ncp->rcline != NULL) {
287 if (!checkflag)
288 free(ncp->rcline);
289 ncp->rcline = NULL;
290 }
291 return 0;
292 }
293
294 /* make sure there is no trn out there reading this newsrc */
295
296 static bool
lock_newsrc(rp)297 lock_newsrc(rp)
298 NEWSRC* rp;
299 {
300 long processnum = 0;
301 char* runninghost = "(Unknown)";
302 char* s;
303
304 if (checkflag)
305 return TRUE;
306
307 s = filexp(RCNAME);
308 if (strEQ(rp->name, s))
309 rp->lockname = savestr(filexp(LOCKNAME));
310 else {
311 sprintf(buf, RCNAME_INFO, rp->name);
312 rp->infoname = savestr(buf);
313 sprintf(buf, RCNAME_LOCK, rp->name);
314 rp->lockname = savestr(buf);
315 }
316
317 tmpfp = fopen(rp->lockname,"r");
318 if (tmpfp != NULL) {
319 if (fgets(buf,LBUFLEN,tmpfp)) {
320 processnum = atol(buf);
321 if (fgets(buf,LBUFLEN,tmpfp) && *buf
322 && *(s = buf + strlen(buf) - 1) == '\n') {
323 *s = '\0';
324 runninghost = buf;
325 }
326 }
327 fclose(tmpfp);
328 }
329 if (processnum) {
330 #ifndef MSDOS
331 #ifdef VERBOSE
332 IF(verbose)
333 printf("\nThe requested newsrc is locked by process %ld on host %s.\n",
334 processnum, runninghost) FLUSH;
335 ELSE
336 #endif
337 #ifdef TERSE
338 printf("\nNewsrc locked by %ld on host %s.\n",processnum,runninghost) FLUSH;
339 #endif
340 termdown(2);
341 if (strNE(runninghost,localhost)) {
342 #ifdef VERBOSE
343 IF(verbose)
344 printf("\n\
345 Since that's not the same host as this one (%s), we must\n\
346 assume that process still exists. To override this check, remove\n\
347 the lock file: %s\n", localhost, rp->lockname) FLUSH;
348 ELSE
349 #endif
350 #ifdef TERSE
351 printf("\nThis host (%s) doesn't match.\nCan't unlock %s.\n",
352 localhost, rp->lockname) FLUSH;
353 #endif
354 termdown(2);
355 if (bizarre)
356 resetty();
357 finalize(0);
358 }
359 if (processnum == our_pid) {
360 #ifdef VERBOSE
361 IF(verbose)
362 printf("\n\
363 Hey, that *my* pid! Your access file is trying to use the same newsrc\n\
364 more than once.\n") FLUSH;
365 ELSE
366 #endif
367 #ifdef TERSE
368 printf("\nAccess file error (our pid detected).\n") FLUSH;
369 #endif
370 termdown(2);
371 return FALSE;
372 }
373 if (kill(processnum, 0) != 0) {
374 /* Process is apparently gone */
375 sleep(2);
376 #ifdef VERBOSE
377 IF(verbose)
378 fputs("\n\
379 That process does not seem to exist anymore. The count of read articles\n\
380 may be incorrect in the last newsgroup accessed by that other (defunct)\n\
381 process.\n\n",stdout) FLUSH;
382 ELSE
383 #endif
384 #ifdef TERSE
385 fputs("\nProcess crashed.\n",stdout) FLUSH;
386 #endif
387 if (lastngname) {
388 #ifdef VERBOSE
389 IF(verbose)
390 printf("(The last newsgroup accessed was %s.)\n\n",
391 lastngname) FLUSH;
392 ELSE
393 #endif
394 #ifdef TERSE
395 printf("(In %s.)\n\n",lastngname) FLUSH;
396 #endif
397 }
398 termdown(2);
399 get_anything();
400 newline();
401 }
402 else {
403 #ifdef VERBOSE
404 IF(verbose)
405 printf("\n\
406 It looks like that process still exists. To override this, remove\n\
407 the lock file: %s\n", rp->lockname) FLUSH;
408 ELSE
409 #endif
410 #ifdef TERSE
411 printf("\nCan't unlock %s.\n", rp->lockname) FLUSH;
412 #endif
413 termdown(2);
414 if (bizarre)
415 resetty();
416 finalize(0);
417 }
418 #endif
419 }
420 tmpfp = fopen(rp->lockname,"w");
421 if (tmpfp == NULL) {
422 printf(cantcreate,rp->lockname) FLUSH;
423 sig_catcher(0);
424 }
425 fprintf(tmpfp,"%ld\n%s\n",our_pid,localhost);
426 fclose(tmpfp);
427 return TRUE;
428 }
429
430 static void
unlock_newsrc(rp)431 unlock_newsrc(rp)
432 NEWSRC* rp;
433 {
434 safefree0(rp->infoname);
435 if (rp->lockname) {
436 UNLINK(rp->lockname);
437 free(rp->lockname);
438 rp->lockname = NULL;
439 }
440 }
441
442 static bool
open_newsrc(rp)443 open_newsrc(rp)
444 NEWSRC* rp;
445 {
446 register NGDATA* np;
447 NGDATA* prev_np;
448 char* some_buf;
449 long length;
450 FILE* rcfp;
451 HASHDATUM data;
452
453 /* make sure the .newsrc file exists */
454
455 if ((rcfp = fopen(rp->name,"r")) == NULL) {
456 rcfp = fopen(rp->name,"w+");
457 if (rcfp == NULL) {
458 printf("\nCan't create %s.\n", rp->name) FLUSH;
459 termdown(2);
460 return FALSE;
461 }
462 some_buf = SUBSCRIPTIONS;
463 #ifdef SUPPORT_NNTP
464 if ((rp->datasrc->flags & DF_REMOTE)
465 && nntp_list("SUBSCRIPTIONS",nullstr,0) == 1) {
466 do {
467 fputs(ser_line,rcfp);
468 fputc('\n',rcfp);
469 if (nntp_gets(ser_line, sizeof ser_line) < 0)
470 break;
471 } while (!nntp_at_list_end(ser_line));
472 }
473 #endif
474 ElseIf (*some_buf && (tmpfp = fopen(filexp(some_buf),"r")) != NULL) {
475 while (fgets(buf,sizeof buf,tmpfp))
476 fputs(buf,rcfp);
477 fclose(tmpfp);
478 }
479 fseek(rcfp, 0L, 0);
480 }
481 else {
482 /* File exists; if zero length and backup isn't, complain */
483 if (fstat(fileno(rcfp),&filestat) < 0) {
484 perror(rp->name);
485 return FALSE;
486 }
487 if (filestat.st_size == 0
488 && stat(rp->oldname,&filestat) >= 0 && filestat.st_size > 0) {
489 printf("Warning: %s is zero length but %s is not.\n",
490 rp->name,rp->oldname);
491 printf("Either recover your newsrc or else remove the backup copy.\n");
492 termdown(2);
493 return FALSE;
494 }
495 /* unlink backup file name and backup current name */
496 UNLINK(rp->oldname);
497 #ifndef NO_FILELINKS
498 safelink(rp->name,rp->oldname);
499 #endif
500 }
501
502 if (!ngdata_list) {
503 /* allocate memory for rc file globals */
504 ngdata_list = new_list(0, 0, sizeof (NGDATA), 200, 0, init_ngnode);
505 newsrc_hash = hashcreate(3001, rcline_cmp);
506 }
507
508 if (ngdata_cnt)
509 prev_np = ngdata_ptr(ngdata_cnt-1);
510 else
511 prev_np = NULL;
512
513 /* read in the .newsrc file */
514
515 while ((some_buf = get_a_line(buf,LBUFLEN,FALSE,rcfp)) != NULL) {
516 length = len_last_line_got; /* side effect of get_a_line */
517 if (length <= 1) /* only a newline??? */
518 continue;
519 np = ngdata_ptr(ngdata_cnt++);
520 if (prev_np)
521 prev_np->next = np;
522 else
523 first_ng = np;
524 np->prev = prev_np;
525 prev_np = np;
526 np->rc = rp;
527 newsgroup_cnt++;
528 if (some_buf[length-1] == '\n')
529 some_buf[--length] = '\0'; /* wipe out newline */
530 if (some_buf == buf)
531 np->rcline = savestr(some_buf); /* make semipermanent copy */
532 else {
533 /*NOSTRICT*/
534 #ifndef lint
535 some_buf = saferealloc(some_buf,(MEM_SIZE)(length+1));
536 #endif
537 np->rcline = some_buf;
538 }
539 if (*some_buf == ' ' || *some_buf == '\t'
540 || strnEQ(some_buf,"options",7)) { /* non-useful line? */
541 np->toread = TR_JUNK;
542 np->subscribechar = ' ';
543 np->numoffset = 0;
544 continue;
545 }
546 parse_rcline(np);
547 data = hashfetch(newsrc_hash, np->rcline, np->numoffset - 1);
548 if (data.dat_ptr) {
549 np->toread = TR_IGNORE;
550 continue;
551 }
552 if (np->subscribechar == NEGCHAR) {
553 np->toread = TR_UNSUB;
554 sethash(np);
555 continue;
556 }
557 newsgroup_toread++;
558
559 /* now find out how much there is to read */
560
561 if (!inlist(buf) || (suppress_cn && foundany && !paranoid))
562 np->toread = TR_NONE; /* no need to calculate now */
563 else
564 set_toread(np, ST_LAX);
565 if (np->toread > TR_NONE) { /* anything unread? */
566 if (!foundany) {
567 starthere = np;
568 foundany = TRUE; /* remember that fact*/
569 }
570 if (suppress_cn) { /* if no listing desired */
571 if (checkflag) /* if that is all they wanted */
572 finalize(1); /* then bomb out */
573 }
574 else {
575 #ifdef VERBOSE
576 IF(verbose)
577 printf("Unread news in %-40s %5ld article%s\n",
578 np->rcline,(long)np->toread,PLURAL(np->toread)) FLUSH;
579 ELSE
580 #endif
581 #ifdef TERSE
582 printf("%s: %ld article%s\n",
583 np->rcline,(long)np->toread,PLURAL(np->toread)) FLUSH;
584 #endif
585 termdown(1);
586 if (int_count) {
587 countdown = 1;
588 int_count = 0;
589 }
590 if (countdown) {
591 if (!--countdown) {
592 fputs("etc.\n",stdout) FLUSH;
593 if (checkflag)
594 finalize(1);
595 suppress_cn = TRUE;
596 }
597 }
598 }
599 }
600 sethash(np);
601 }
602 if (prev_np) {
603 prev_np->next = NULL;
604 last_ng = prev_np;
605 }
606 fclose(rcfp); /* close .newsrc */
607 #ifdef NO_FILELINKS
608 UNLINK(rp->oldname);
609 RENAME(rp->name,rp->oldname);
610 rp->flags |= RF_RCCHANGED;
611 #endif
612 if (rp->infoname) {
613 if ((tmpfp = fopen(rp->infoname,"r")) != NULL) {
614 if (fgets(buf,sizeof buf,tmpfp) != NULL) {
615 long actnum, descnum;
616 char* s;
617 buf[strlen(buf)-1] = '\0';
618 if ((s = index(buf, ':')) != NULL && s[1] == ' ' && s[2]) {
619 safefree0(lastngname);
620 lastngname = savestr(s+2);
621 }
622 if (fscanf(tmpfp,"New-Group-State: %ld,%ld,%ld",
623 &lastnewtime,&actnum,&descnum) == 3) {
624 rp->datasrc->act_sf.recent_cnt = actnum;
625 rp->datasrc->desc_sf.recent_cnt = descnum;
626 }
627 }
628 }
629 }
630 else {
631 readlast();
632 #ifdef SUPPORT_NNTP
633 if (rp->datasrc->flags & DF_REMOTE) {
634 rp->datasrc->act_sf.recent_cnt = lastactsiz;
635 rp->datasrc->desc_sf.recent_cnt = lastextranum;
636 }
637 else
638 #endif
639 {
640 rp->datasrc->act_sf.recent_cnt = lastextranum;
641 rp->datasrc->desc_sf.recent_cnt = 0;
642 }
643 }
644 rp->datasrc->lastnewgrp = lastnewtime;
645
646 if (paranoid && !checkflag)
647 cleanup_newsrc(rp);
648 return TRUE;
649 }
650
651 /* Initialize the memory for an entire node's worth of article's */
652 static void
init_ngnode(list,node)653 init_ngnode(list, node)
654 LIST* list;
655 LISTNODE* node;
656 {
657 register ART_NUM i;
658 register NGDATA* np;
659 bzero(node->data, list->items_per_node * list->item_size);
660 for (i = node->low, np = (NGDATA*)node->data; i <= node->high; i++, np++)
661 np->num = i;
662 }
663
664 static void
parse_rcline(np)665 parse_rcline(np)
666 register NGDATA* np;
667 {
668 char* s;
669 int len;
670
671 for (s=np->rcline; *s && *s!=':' && *s!=NEGCHAR && !isspace(*s); s++) ;
672 len = s - np->rcline;
673 if ((!*s || isspace(*s)) && !checkflag) {
674 #ifndef lint
675 np->rcline = saferealloc(np->rcline,(MEM_SIZE)len + 3);
676 #endif
677 s = np->rcline + len;
678 strcpy(s, ": ");
679 }
680 if (*s == ':' && s[1] && s[2] == '0') {
681 np->flags |= NF_UNTHREADED;
682 s[2] = '1';
683 }
684 np->subscribechar = *s; /* salt away the : or ! */
685 np->numoffset = len + 1; /* remember where the numbers are */
686 *s = '\0'; /* null terminate newsgroup name */
687 }
688
689 void
abandon_ng(np)690 abandon_ng(np)
691 NGDATA* np;
692 {
693 char* some_buf = NULL;
694 FILE* rcfp;
695
696 /* open newsrc backup copy and try to find the prior value for the group. */
697 if ((rcfp = fopen(np->rc->oldname, "r")) != NULL) {
698 int length = np->numoffset - 1;
699
700 while ((some_buf = get_a_line(buf,LBUFLEN,FALSE,rcfp)) != NULL) {
701 if (len_last_line_got <= 0)
702 continue;
703 some_buf[len_last_line_got-1] = '\0'; /* wipe out newline */
704 if ((some_buf[length] == ':' || some_buf[length] == NEGCHAR)
705 && strnEQ(np->rcline, some_buf, length)) {
706 break;
707 }
708 if (some_buf != buf)
709 free(some_buf);
710 }
711 fclose(rcfp);
712 } else if (errno != ENOENT) {
713 printf("Unable to open %s.\n", np->rc->oldname) FLUSH;
714 termdown(1);
715 return;
716 }
717 if (some_buf == NULL) {
718 some_buf = np->rcline + np->numoffset;
719 if (*some_buf == ' ')
720 some_buf++;
721 *some_buf = '\0';
722 np->abs1st = 0; /* force group to be re-calculated */
723 }
724 else {
725 free(np->rcline);
726 if (some_buf == buf)
727 np->rcline = savestr(some_buf);
728 else {
729 /*NOSTRICT*/
730 #ifndef lint
731 some_buf = saferealloc(some_buf, (MEM_SIZE)(len_last_line_got));
732 #endif /* lint */
733 np->rcline = some_buf;
734 }
735 }
736 parse_rcline(np);
737 if (np->subscribechar == NEGCHAR)
738 np->subscribechar = ':';
739 np->rc->flags |= RF_RCCHANGED;
740 set_toread(np, ST_LAX);
741 }
742
743 /* try to find or add an explicitly specified newsgroup */
744 /* returns TRUE if found or added, FALSE if not. */
745 /* assumes that we are chdir'ed to NEWSSPOOL */
746
747 bool
get_ng(what,flags)748 get_ng(what, flags)
749 char* what;
750 int flags;
751 {
752 char* ntoforget;
753 char promptbuf[128];
754 int autosub;
755
756 #ifdef VERBOSE
757 IF(verbose)
758 ntoforget = "Type n to forget about this newsgroup.\n";
759 ELSE
760 #endif
761 #ifdef TERSE
762 ntoforget = "n to forget it.\n";
763 #endif
764 if (index(what,'/')) {
765 dingaling();
766 printf("\nBad newsgroup name.\n") FLUSH;
767 termdown(2);
768 check_fuzzy_match:
769 #ifdef EDIT_DISTANCE
770 if (fuzzyGet && (flags & GNG_FUZZY)) {
771 flags &= ~GNG_FUZZY;
772 if (find_close_match())
773 what = ngname;
774 else
775 return FALSE;
776 } else
777 #endif
778 return FALSE;
779 }
780 set_ngname(what);
781 ngptr = find_ng(ngname);
782 if (ngptr == NULL) { /* not in .newsrc? */
783 NEWSRC* rp;
784 for (rp = multirc->first; rp; rp = rp->next) {
785 if (!ALLBITS(rp->flags, RF_ADD_GROUPS | RF_ACTIVE))
786 continue;
787 /*$$ this may scan a datasrc multiple times... */
788 if (find_actgrp(rp->datasrc,buf,ngname,ngname_len,(ART_NUM)0))
789 break; /*$$ let them choose which server */
790 }
791 if (!rp) {
792 dingaling();
793 #ifdef VERBOSE
794 IF(verbose)
795 printf("\nNewsgroup %s does not exist!\n",ngname) FLUSH;
796 ELSE
797 #endif
798 #ifdef TERSE
799 printf("\nNo %s!\n",ngname) FLUSH;
800 #endif
801 termdown(2);
802 if (novice_delays)
803 sleep(2);
804 goto check_fuzzy_match;
805 }
806 if (mode != 'i' || !(autosub = auto_subscribe(ngname)))
807 autosub = addnewbydefault;
808 if (autosub) {
809 if (append_unsub) {
810 printf("(Adding %s to end of your .newsrc %ssubscribed)\n",
811 ngname, (autosub == ADDNEW_SUB)? nullstr : "un") FLUSH;
812 termdown(1);
813 ngptr = add_newsgroup(rp, ngname, autosub);
814 } else {
815 if (autosub == ADDNEW_SUB) {
816 printf("(Subscribing to %s)\n", ngname) FLUSH;
817 termdown(1);
818 ngptr = add_newsgroup(rp, ngname, autosub);
819 } else {
820 printf("(Ignoring %s)\n", ngname) FLUSH;
821 termdown(1);
822 return FALSE;
823 }
824 }
825 flags &= ~GNG_RELOC;
826 } else {
827 #ifdef VERBOSE
828 IF(verbose)
829 sprintf(promptbuf,"\nNewsgroup %s not in .newsrc -- subscribe?",ngname);
830 ELSE
831 #endif
832 #ifdef TERSE
833 sprintf(promptbuf,"\nSubscribe %s?",ngname);
834 #endif
835 reask_add:
836 in_char(promptbuf,'A',"ynYN");
837 #ifdef VERIFY
838 printcmd();
839 #endif
840 newline();
841 if (*buf == 'h') {
842 #ifdef VERBOSE
843 IF(verbose) {
844 printf("Type y or SP to subscribe to %s.\n\
845 Type Y to subscribe to this and all remaining new groups.\n\
846 Type N to leave all remaining new groups unsubscribed.\n", ngname) FLUSH;
847 termdown(3);
848 }
849 ELSE
850 #endif
851 #ifdef TERSE
852 {
853 fputs("\
854 y or SP to subscribe, Y to subscribe all new groups, N to unsubscribe all\n",
855 stdout) FLUSH;
856 termdown(1);
857 }
858 #endif
859 fputs(ntoforget,stdout) FLUSH;
860 termdown(1);
861 goto reask_add;
862 }
863 else if (*buf == 'n' || *buf == 'q') {
864 if (append_unsub)
865 ngptr = add_newsgroup(rp, ngname, NEGCHAR);
866 return FALSE;
867 }
868 else if (*buf == 'y') {
869 ngptr = add_newsgroup(rp, ngname, ':');
870 flags |= GNG_RELOC;
871 }
872 else if (*buf == 'Y') {
873 addnewbydefault = ADDNEW_SUB;
874 if (append_unsub)
875 printf("(Adding %s to end of your .newsrc subscribed)\n",
876 ngname) FLUSH;
877 else
878 printf("(Subscribing to %s)\n", ngname) FLUSH;
879 termdown(1);
880 ngptr = add_newsgroup(rp, ngname, ':');
881 flags &= ~GNG_RELOC;
882 }
883 else if (*buf == 'N') {
884 addnewbydefault = ADDNEW_UNSUB;
885 if (append_unsub) {
886 printf("(Adding %s to end of your .newsrc unsubscribed)\n",
887 ngname) FLUSH;
888 termdown(1);
889 ngptr = add_newsgroup(rp, ngname, NEGCHAR);
890 flags &= ~GNG_RELOC;
891 } else {
892 printf("(Ignoring %s)\n", ngname) FLUSH;
893 termdown(1);
894 return FALSE;
895 }
896 }
897 else {
898 fputs(hforhelp,stdout) FLUSH;
899 termdown(1);
900 settle_down();
901 goto reask_add;
902 }
903 }
904 }
905 else if (mode == 'i') /* adding new groups during init? */
906 return FALSE;
907 else if (ngptr->subscribechar == NEGCHAR) {/* unsubscribed? */
908 #ifdef VERBOSE
909 IF(verbose)
910 sprintf(promptbuf,
911 "\nNewsgroup %s is unsubscribed -- resubscribe?",ngname)
912 FLUSH;
913 ELSE
914 #endif
915 #ifdef TERSE
916 sprintf(promptbuf,"\nResubscribe %s?",ngname)
917 FLUSH;
918 #endif
919 reask_unsub:
920 in_char(promptbuf,'R',"yn");
921 #ifdef VERIFY
922 printcmd();
923 #endif
924 newline();
925 if (*buf == 'h') {
926 #ifdef VERBOSE
927 IF(verbose)
928 printf("Type y or SP to resubscribe to %s.\n", ngname) FLUSH;
929 ELSE
930 #endif
931 #ifdef TERSE
932 fputs("y or SP to resubscribe.\n",stdout) FLUSH;
933 #endif
934 fputs(ntoforget,stdout) FLUSH;
935 termdown(2);
936 goto reask_unsub;
937 }
938 else if (*buf == 'n' || *buf == 'q') {
939 return FALSE;
940 }
941 else if (*buf == 'y') {
942 register char* cp;
943 cp = ngptr->rcline + ngptr->numoffset;
944 ngptr->flags = (*cp && cp[1] == '0' ? NF_UNTHREADED : 0);
945 ngptr->subscribechar = ':';
946 ngptr->rc->flags |= RF_RCCHANGED;
947 flags &= ~GNG_RELOC;
948 }
949 else {
950 fputs(hforhelp,stdout) FLUSH;
951 termdown(1);
952 settle_down();
953 goto reask_unsub;
954 }
955 }
956
957 /* now calculate how many unread articles in newsgroup */
958
959 set_toread(ngptr, ST_STRICT);
960 #ifdef RELOCATE
961 if (flags & GNG_RELOC) {
962 if (!relocate_newsgroup(ngptr,-1))
963 return FALSE;
964 }
965 #endif
966 return ngptr->toread >= TR_NONE;
967 }
968
969 /* add a newsgroup to the newsrc file (eventually) */
970
971 static NGDATA*
add_newsgroup(rp,ngn,c)972 add_newsgroup(rp, ngn, c)
973 NEWSRC* rp;
974 char* ngn;
975 char_int c;
976 {
977 register NGDATA* np;
978
979 np = ngdata_ptr(ngdata_cnt++);
980 np->prev = last_ng;
981 if (last_ng)
982 last_ng->next = np;
983 else
984 first_ng = np;
985 np->next = NULL;
986 last_ng = np;
987 newsgroup_cnt++;
988
989 np->rc = rp;
990 np->numoffset = strlen(ngn) + 1;
991 np->rcline = safemalloc((MEM_SIZE)(np->numoffset + 2));
992 strcpy(np->rcline,ngn); /* and copy over the name */
993 strcpy(np->rcline + np->numoffset, " ");
994 np->subscribechar = c; /* subscribe or unsubscribe */
995 if (c != NEGCHAR)
996 newsgroup_toread++;
997 np->toread = TR_NONE; /* just for prettiness */
998 sethash(np); /* so we can find it again */
999 rp->flags |= RF_RCCHANGED;
1000 return np;
1001 }
1002
1003 #ifdef RELOCATE
1004 bool
relocate_newsgroup(move_np,newnum)1005 relocate_newsgroup(move_np,newnum)
1006 NGDATA* move_np;
1007 NG_NUM newnum;
1008 {
1009 NGDATA* np;
1010 int i;
1011 char* dflt = (move_np!=current_ng ? "$^.Lq" : "$^Lq");
1012 int save_sort = sel_sort;
1013
1014 if (sel_newsgroupsort != SS_NATURAL) {
1015 if (newnum < 0) {
1016 /* ask if they want to keep the current order */
1017 in_char("Sort newsrc(s) using current sort order?", 'D', "yn"); /*$$ !'D' */
1018 #ifdef VERIFY
1019 printcmd();
1020 #endif
1021 newline();
1022 if (*buf == 'y')
1023 set_selector(SM_NEWSGROUP, SS_NATURAL);
1024 else {
1025 sel_sort = SS_NATURAL;
1026 sel_direction = 1;
1027 sort_newsgroups();
1028 }
1029 }
1030 else {
1031 sel_sort = SS_NATURAL;
1032 sel_direction = 1;
1033 sort_newsgroups();
1034 }
1035 }
1036
1037 starthere = NULL; /* Disable this optimization */
1038 if (move_np != last_ng) {
1039 if (move_np->prev)
1040 move_np->prev->next = move_np->next;
1041 else
1042 first_ng = move_np->next;
1043 move_np->next->prev = move_np->prev;
1044
1045 move_np->prev = last_ng;
1046 move_np->next = NULL;
1047 last_ng->next = move_np;
1048 last_ng = move_np;
1049 }
1050
1051 /* Renumber the groups according to current order */
1052 for (np = first_ng, i = 0; np; np = np->next, i++)
1053 np->num = i;
1054 move_np->rc->flags |= RF_RCCHANGED;
1055
1056 if (newnum < 0) {
1057 reask_reloc:
1058 unflush_output(); /* disable any ^O in effect */
1059 #ifdef VERBOSE
1060 IF(verbose)
1061 printf("\nPut newsgroup where? [%s] ", dflt);
1062 ELSE
1063 #endif
1064 #ifdef TERSE
1065 printf("\nPut where? [%s] ", dflt);
1066 #endif
1067 fflush(stdout);
1068 termdown(1);
1069 reinp_reloc:
1070 eat_typeahead();
1071 getcmd(buf);
1072 if (errno || *buf == '\f') /* if return from stop signal */
1073 goto reask_reloc; /* give them a prompt again */
1074 setdef(buf,dflt);
1075 #ifdef VERIFY
1076 printcmd();
1077 #endif
1078 if (*buf == 'h') {
1079 #ifdef VERBOSE
1080 IF(verbose) {
1081 printf("\n\n\
1082 Type ^ to put the newsgroup first (position 0).\n\
1083 Type $ to put the newsgroup last (position %d).\n", newsgroup_cnt-1);
1084 printf("\
1085 Type . to put it before the current newsgroup.\n");
1086 printf("\
1087 Type -newsgroup name to put it before that newsgroup.\n\
1088 Type +newsgroup name to put it after that newsgroup.\n\
1089 Type a number between 0 and %d to put it at that position.\n", newsgroup_cnt-1);
1090 printf("\
1091 Type L for a listing of newsgroups and their positions.\n\
1092 Type q to abort the current action.\n") FLUSH;
1093 }
1094 ELSE
1095 #endif
1096 #ifdef TERSE
1097 {
1098 printf("\n\n\
1099 ^ to put newsgroup first (pos 0).\n\
1100 $ to put last (pos %d).\n", newsgroup_cnt-1);
1101 printf("\
1102 . to put before current newsgroup.\n");
1103 printf("\
1104 -newsgroup to put before newsgroup.\n\
1105 +newsgroup to put after.\n\
1106 number in 0-%d to put at that pos.\n", newsgroup_cnt-1);
1107 printf("\
1108 L for list of newsrc.\n\
1109 q to abort\n") FLUSH;
1110 }
1111 #endif
1112 termdown(10);
1113 goto reask_reloc;
1114 }
1115 else if (*buf == 'q')
1116 return FALSE;
1117 else if (*buf == 'L') {
1118 newline();
1119 list_newsgroups();
1120 goto reask_reloc;
1121 }
1122 else if (isdigit(*buf)) {
1123 if (!finish_command(TRUE)) /* get rest of command */
1124 goto reinp_reloc;
1125 newnum = atol(buf);
1126 if (newnum < 0)
1127 newnum = 0;
1128 if (newnum >= newsgroup_cnt)
1129 newnum = newsgroup_cnt-1;
1130 }
1131 else if (*buf == '^') {
1132 newline();
1133 newnum = 0;
1134 }
1135 else if (*buf == '$') {
1136 newnum = newsgroup_cnt-1;
1137 }
1138 else if (*buf == '.') {
1139 newline();
1140 newnum = current_ng->num;
1141 }
1142 else if (*buf == '-' || *buf == '+') {
1143 if (!finish_command(TRUE)) /* get rest of command */
1144 goto reinp_reloc;
1145 np = find_ng(buf+1);
1146 if (np == NULL) {
1147 fputs("Not found.",stdout) FLUSH;
1148 goto reask_reloc;
1149 }
1150 newnum = np->num;
1151 if (*buf == '+')
1152 newnum++;
1153 }
1154 else {
1155 printf("\n%s",hforhelp) FLUSH;
1156 termdown(2);
1157 settle_down();
1158 goto reask_reloc;
1159 }
1160 }
1161 if (newnum < newsgroup_cnt-1) {
1162 for (np = first_ng; np; np = np->next)
1163 if (np->num >= newnum)
1164 break;
1165 if (!np || np == move_np)
1166 return FALSE; /* This can't happen... */
1167
1168 last_ng = move_np->prev;
1169 last_ng->next = NULL;
1170
1171 move_np->prev = np->prev;
1172 move_np->next = np;
1173
1174 if (np->prev)
1175 np->prev->next = move_np;
1176 else
1177 first_ng = move_np;
1178 np->prev = move_np;
1179
1180 move_np->num = newnum++;
1181 for (; np; np = np->next, newnum++)
1182 np->num = newnum;
1183 }
1184 if (sel_newsgroupsort != SS_NATURAL) {
1185 sel_sort = sel_newsgroupsort;
1186 sort_newsgroups();
1187 sel_sort = save_sort;
1188 }
1189 return TRUE;
1190 }
1191 #endif /* RELOCATE */
1192
1193 /* List out the newsrc with annotations */
1194
1195 void
list_newsgroups()1196 list_newsgroups()
1197 {
1198 register NGDATA* np;
1199 register NG_NUM i;
1200 char tmpbuf[2048];
1201 static char* status[] = {"(READ)","(UNSUB)","(DUP)","(BOGUS)","(JUNK)"};
1202
1203 page_start();
1204 print_lines(" # Status Newsgroup\n",STANDOUT);
1205 for (np = first_ng, i = 0; np && !int_count; np = np->next, i++) {
1206 if (np->toread >= 0)
1207 set_toread(np, ST_LAX);
1208 *(np->rcline + np->numoffset - 1) = np->subscribechar;
1209 if (np->toread > 0)
1210 sprintf(tmpbuf,"%3d %6ld ",i,(long)np->toread);
1211 else
1212 sprintf(tmpbuf,"%3d %7s ",i,status[-np->toread]);
1213 safecpy(tmpbuf+13, np->rcline, sizeof tmpbuf - 13);
1214 *(np->rcline + np->numoffset - 1) = '\0';
1215 if (print_lines(tmpbuf,NOMARKING) != 0)
1216 break;
1217 }
1218 int_count = 0;
1219 }
1220
1221 /* find a newsgroup in any newsrc */
1222
1223 NGDATA*
find_ng(ngnam)1224 find_ng(ngnam)
1225 char* ngnam;
1226 {
1227 HASHDATUM data;
1228
1229 data = hashfetch(newsrc_hash, ngnam, strlen(ngnam));
1230 return (NGDATA*)data.dat_ptr;
1231 }
1232
1233 void
cleanup_newsrc(rp)1234 cleanup_newsrc(rp)
1235 NEWSRC* rp;
1236 {
1237 register NGDATA* np;
1238 register NG_NUM bogosity = 0;
1239
1240 #ifdef VERBOSE
1241 IF(verbose)
1242 printf("Checking out '%s' -- hang on a second...\n",rp->name) FLUSH;
1243 ELSE
1244 #endif
1245 #ifdef TERSE
1246 printf("Checking '%s' -- hang on...\n",rp->name) FLUSH;
1247 #endif
1248 termdown(1);
1249 for (np = first_ng; np; np = np->next) {
1250 /*#ifdef CHECK_ALL_BOGUS $$ what is this? */
1251 if (np->toread >= TR_UNSUB)
1252 set_toread(np, ST_LAX); /* this may reset the group or declare it bogus */
1253 /*#endif*/
1254 if (np->toread == TR_BOGUS)
1255 bogosity++;
1256 }
1257 for (np = last_ng; np && np->toread == TR_BOGUS; np = np->prev)
1258 bogosity--; /* discount already moved ones */
1259 if (newsgroup_cnt > 5 && bogosity > newsgroup_cnt / 2) {
1260 fputs(
1261 "It looks like the active file is messed up. Contact your news administrator,\n\
1262 ",stdout);
1263 fputs(
1264 "leave the \"bogus\" groups alone, and they may come back to normal. Maybe.\n\
1265 ",stdout) FLUSH;
1266 termdown(2);
1267 }
1268 #ifdef RELOCATE
1269 else if (bogosity) {
1270 NGDATA* prev_np;
1271 #ifdef VERBOSE
1272 IF(verbose)
1273 printf("Moving bogus newsgroups to the end of '%s'.\n",rp->name) FLUSH;
1274 ELSE
1275 #endif
1276 #ifdef TERSE
1277 fputs("Moving boguses to the end.\n",stdout) FLUSH;
1278 #endif
1279 termdown(1);
1280 while (np) {
1281 prev_np = np->prev;
1282 if (np->toread == TR_BOGUS)
1283 relocate_newsgroup(np, newsgroup_cnt-1);
1284 np = prev_np;
1285 }
1286 rp->flags |= RF_RCCHANGED;
1287 #ifdef DELBOGUS
1288 reask_bogus:
1289 in_char("Delete bogus newsgroups?", 'D', "ny");
1290 #ifdef VERIFY
1291 printcmd();
1292 #endif
1293 newline();
1294 if (*buf == 'h') {
1295 #ifdef VERBOSE
1296 IF(verbose) {
1297 fputs("\
1298 Type y to delete bogus newsgroups.\n\
1299 Type n or SP to leave them at the end in case they return.\n\
1300 ",stdout) FLUSH;
1301 termdown(2);
1302 }
1303 ELSE
1304 #endif
1305 #ifdef TERSE
1306 {
1307 fputs("y to delete, n to keep\n",stdout) FLUSH;
1308 termdown(1);
1309 }
1310 #endif
1311 goto reask_bogus;
1312 }
1313 else if (*buf == 'n' || *buf == 'q')
1314 ;
1315 else if (*buf == 'y') {
1316 for (np = last_ng; np && np->toread == TR_BOGUS; np = np->prev) {
1317 hashdelete(newsrc_hash, np->rcline, np->numoffset - 1);
1318 clear_ngitem((char*)np,0);
1319 newsgroup_cnt--;
1320 }
1321 rp->flags |= RF_RCCHANGED; /*$$ needed? */
1322 last_ng = np;
1323 if (np)
1324 np->next = NULL;
1325 else
1326 first_ng = NULL;
1327 if (current_ng && !current_ng->rcline)
1328 current_ng = first_ng;
1329 if (recent_ng && !recent_ng->rcline)
1330 recent_ng = first_ng;
1331 if (ngptr && !ngptr->rcline)
1332 ngptr = first_ng;
1333 if (sel_page_np && !sel_page_np->rcline)
1334 sel_page_np = NULL;
1335 }
1336 else {
1337 fputs(hforhelp,stdout) FLUSH;
1338 termdown(1);
1339 settle_down();
1340 goto reask_bogus;
1341 }
1342 #endif /* DELBOGUS */
1343 }
1344 #else /* !RELOCATE */
1345 #ifdef VERBOSE
1346 IF(verbose)
1347 printf("You should edit bogus newsgroups out of '%s'.\n",rp->name) FLUSH;
1348 ELSE
1349 #endif
1350 #ifdef TERSE
1351 printf("Edit boguses from '%s'.\n",rp->name) FLUSH;
1352 #endif
1353 termdown(1);
1354 #endif /* !RELOCATE */
1355 paranoid = FALSE;
1356 }
1357
1358 /* make an entry in the hash table for the current newsgroup */
1359
1360 void
sethash(np)1361 sethash(np)
1362 NGDATA* np;
1363 {
1364 HASHDATUM data;
1365 data.dat_ptr = (char*)np;
1366 data.dat_len = np->numoffset - 1;
1367 hashstore(newsrc_hash, np->rcline, data.dat_len, data);
1368 }
1369
1370 static int
rcline_cmp(key,keylen,data)1371 rcline_cmp(key, keylen, data)
1372 char* key;
1373 int keylen;
1374 HASHDATUM data;
1375 {
1376 /* We already know that the lengths are equal, just compare the strings */
1377 return bcmp(key, ((NGDATA*)data.dat_ptr)->rcline, keylen);
1378 }
1379
1380 /* checkpoint the newsrc(s) */
1381
1382 void
checkpoint_newsrcs()1383 checkpoint_newsrcs()
1384 {
1385 #ifdef DEBUG
1386 if (debug & DEB_CHECKPOINTING) {
1387 fputs("(ckpt)",stdout);
1388 fflush(stdout);
1389 }
1390 #endif
1391 if (doing_ng)
1392 bits_to_rc(); /* do not restore M articles */
1393 if (!write_newsrcs(multirc))
1394 get_anything();
1395 #ifdef DEBUG
1396 if (debug & DEB_CHECKPOINTING) {
1397 fputs("(done)",stdout);
1398 fflush(stdout);
1399 }
1400 #endif
1401 }
1402
1403 /* write out the (presumably) revised newsrc(s) */
1404
1405 bool
write_newsrcs(mptr)1406 write_newsrcs(mptr)
1407 MULTIRC* mptr;
1408 {
1409 NEWSRC* rp;
1410 register NGDATA* np;
1411 int save_sort = sel_sort;
1412 FILE* rcfp;
1413 bool total_success = TRUE;
1414
1415 if (!mptr)
1416 return TRUE;
1417
1418 if (sel_newsgroupsort != SS_NATURAL) {
1419 sel_sort = SS_NATURAL;
1420 sel_direction = 1;
1421 sort_newsgroups();
1422 }
1423
1424 for (rp = mptr->first; rp; rp = rp->next) {
1425 if (!(rp->flags & RF_ACTIVE))
1426 continue;
1427
1428 if (rp->infoname) {
1429 if ((tmpfp = fopen(rp->infoname, "w")) != NULL) {
1430 fprintf(tmpfp,"Last-Group: %s\nNew-Group-State: %ld,%ld,%ld\n",
1431 ngname? ngname : nullstr,rp->datasrc->lastnewgrp,
1432 rp->datasrc->act_sf.recent_cnt,
1433 rp->datasrc->desc_sf.recent_cnt);
1434 fclose(tmpfp);
1435 }
1436 }
1437 else {
1438 readlast();
1439 #ifdef SUPPORT_NNTP
1440 if (rp->datasrc->flags & DF_REMOTE) {
1441 lastactsiz = rp->datasrc->act_sf.recent_cnt;
1442 lastextranum = rp->datasrc->desc_sf.recent_cnt;
1443 }
1444 else
1445 #endif
1446 lastextranum = rp->datasrc->act_sf.recent_cnt;
1447 lastnewtime = rp->datasrc->lastnewgrp;
1448 writelast();
1449 }
1450
1451 if (!(rp->flags & RF_RCCHANGED))
1452 continue;
1453
1454 rcfp = fopen(rp->newname, "w");
1455 if (rcfp == NULL) {
1456 printf(cantrecreate,rp->name) FLUSH;
1457 total_success = FALSE;
1458 continue;
1459 }
1460 #ifndef MSDOS
1461 if (stat(rp->name,&filestat)>=0) { /* preserve permissions */
1462 chmod(rp->newname,filestat.st_mode&0666);
1463 chown(rp->newname,filestat.st_uid,filestat.st_gid);
1464 }
1465 #endif
1466 /* write out each line*/
1467
1468 for (np = first_ng; np; np = np->next) {
1469 register char* delim;
1470 if (np->rc != rp)
1471 continue;
1472 if (np->numoffset) {
1473 delim = np->rcline + np->numoffset - 1;
1474 *delim = np->subscribechar;
1475 if ((np->flags & NF_UNTHREADED) && delim[2] == '1')
1476 delim[2] = '0';
1477 }
1478 else
1479 delim = NULL;
1480 #ifdef DEBUG
1481 if (debug & DEB_NEWSRC_LINE) {
1482 printf("%s\n",np->rcline) FLUSH;
1483 termdown(1);
1484 }
1485 #endif
1486 if (fprintf(rcfp,"%s\n",np->rcline) < 0) {
1487 fclose(rcfp); /* close new newsrc */
1488 goto write_error;
1489 }
1490 if (delim) {
1491 *delim = '\0'; /* might still need this line */
1492 if ((np->flags & NF_UNTHREADED) && delim[2] == '0')
1493 delim[2] = '1';
1494 }
1495 }
1496 fflush(rcfp);
1497 /* fclose is the only sure test for full disks via NFS */
1498 if (ferror(rcfp)) {
1499 fclose(rcfp);
1500 goto write_error;
1501 }
1502 if (fclose(rcfp) == EOF) {
1503 write_error:
1504 printf(cantrecreate,rp->name) FLUSH;
1505 UNLINK(rp->newname);
1506 total_success = FALSE;
1507 continue;
1508 }
1509 rp->flags &= ~RF_RCCHANGED;
1510
1511 UNLINK(rp->name);
1512 RENAME(rp->newname,rp->name);
1513 }
1514
1515 if (sel_newsgroupsort != SS_NATURAL) {
1516 sel_sort = sel_newsgroupsort;
1517 sort_newsgroups();
1518 sel_sort = save_sort;
1519 }
1520 return total_success;
1521 }
1522
1523 void
get_old_newsrcs(mptr)1524 get_old_newsrcs(mptr)
1525 MULTIRC* mptr;
1526 {
1527 NEWSRC* rp;
1528
1529 if (mptr) {
1530 for (rp = mptr->first; rp; rp = rp->next) {
1531 if (rp->flags & RF_ACTIVE) {
1532 UNLINK(rp->newname);
1533 RENAME(rp->name,rp->newname);
1534 RENAME(rp->oldname,rp->name);
1535 }
1536 }
1537 }
1538 }
1539