tin  2.4.4
About: TIN is a threaded NNTP and spool based UseNet newsreader.
  Fossies Dox: tin-2.4.4.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

active.c
Go to the documentation of this file.
1 /*
2  * Project : tin - a Usenet reader
3  * Module : active.c
4  * Author : I. Lea
5  * Created : 1992-02-16
6  * Updated : 2019-01-28
7  * Notes :
8  *
9  * Copyright (c) 1992-2020 Iain Lea <iain@bricbrac.de>
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  *
16  * 1. Redistributions of source code must retain the above copyright notice,
17  * this list of conditions and the following disclaimer.
18  *
19  * 2. Redistributions in binary form must reproduce the above copyright
20  * notice, this list of conditions and the following disclaimer in the
21  * documentation and/or other materials provided with the distribution.
22  *
23  * 3. Neither the name of the copyright holder nor the names of its
24  * contributors may be used to endorse or promote products derived from
25  * this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 
41 #ifndef TIN_H
42 # include "tin.h"
43 #endif /* !TIN_H */
44 #ifndef TCURSES_H
45 # include "tcurses.h"
46 #endif /* !TCURSES_H */
47 
48 /*
49  * List of allowed separator chars in active file
50  * unused in parse_active_line()
51  */
52 #define ACTIVE_SEP " \n"
53 
54 #ifdef NNTP_ABLE
55 # ifdef DISABLE_PIPELINING
56 # define NUM_SIMULTANEOUS_GROUP_COMMAND 1
57 # else
58 # define NUM_SIMULTANEOUS_GROUP_COMMAND 50
59 # endif /* DISABLE_PIPELINING */
60 #endif /* NNTP_ABLE */
61 
63 static time_t active_timestamp; /* time active file read (local) */
64 
65 
66 /*
67  * Local prototypes
68  */
69 static FILE *open_newgroups_fp(int idx);
70 static FILE *open_news_active_fp(void);
71 static int check_for_any_new_groups(void);
72 static void active_add(struct t_group *ptr, t_artnum count, t_artnum max, t_artnum min, const char *moderated);
73 static void append_group_line(char *active_file, char *group_path, t_artnum art_max, t_artnum art_min, char *base_dir);
74 static void make_group_list(char *active_file, char *base_dir, char *fixed_base, char *group_path);
75 static void read_active_file(void);
76 static void read_newsrc_active_file(void);
77 static void subscribe_new_group(char *group, char *autosubscribe, char *autounsubscribe);
78 #ifdef NNTP_ABLE
79  static t_bool do_read_newsrc_active_file(FILE *fp);
80  static t_bool parse_count_line(char *line, t_artnum *max, t_artnum *min, t_artnum *count, char *moderated);
81  static void read_active_counts(void);
82 #else
83  static void do_read_newsrc_active_file(FILE *fp);
84 #endif /* NNTP_ABLE */
85 
86 
87 t_bool
89  void)
90 {
92  (int) (time(NULL) - active_timestamp) >= tinrc.reread_active_file_secs));
93 }
94 
95 
96 /*
97  * Resync active file when reread_active_file_secs have passed or
98  * force_reread_active_file is set.
99  * Return TRUE if a reread was performed
100  */
101 t_bool
103  void)
104 {
105  char *old_group = NULL;
106  t_bool command_line = FALSE;
107 
109  return FALSE;
110 
112 
113  if (selmenu.curr >= 0 && selmenu.max)
114  old_group = my_strdup(CURR_GROUP.name);
115 
116  write_newsrc();
118 
119 #ifdef HAVE_MH_MAIL_HANDLING
120  read_mail_active_file();
121 #endif /* HAVE_MH_MAIL_HANDLING */
122 
123  if (read_cmd_line_groups())
124  command_line = TRUE;
125 
126  read_newsrc(newsrc, bool_not(command_line));
127 
128  if (command_line) /* Can't show only unread groups with cmd line groups */
130  else
131  toggle_my_groups(old_group);
132 
133  FreeIfNeeded(old_group);
135 
136  return TRUE;
137 }
138 
139 
140 /*
141  * Populate a slot in the active[] array
142  * TODO: 1) Have a preinitialised default slot and block assign it for speed
143  * TODO: 2) Lump count/max/min/moderat into a t_active, big patch but much cleaner throughout tin
144  */
145 static void
147  struct t_group *ptr,
148  t_artnum count,
149  t_artnum max,
150  t_artnum min,
151  const char *moderated)
152 {
153  /* name - pre-initialised when group is made */
154  ptr->aliasedto = ((moderated[0] == '=') ? my_strdup(moderated + 1) : NULL);
155  ptr->description = NULL;
156  /* spool - see below */
157  ptr->moderated = moderated[0];
158  ptr->count = count;
159  ptr->xmax = max;
160  ptr->xmin = min;
161  /* type - see below */
162  ptr->inrange = FALSE;
163  ptr->read_during_session = FALSE;
164  ptr->art_was_posted = FALSE;
165  ptr->subscribed = FALSE; /* not in my_group[] yet */
166  ptr->newgroup = FALSE;
167  ptr->bogus = FALSE;
168  ptr->next = -1; /* hash chain */
169  ptr->newsrc.xbitmap = (t_bitmap *) 0;
170  ptr->attribute = (struct t_attribute *) 0;
171  ptr->glob_filter = &glob_filter;
172  set_default_bitmap(ptr);
173 
174  if (moderated[0] == '/') {
175  ptr->type = GROUP_TYPE_SAVE;
176  ptr->spooldir = my_strdup(moderated); /* TODO: Unix'ism, other OSs need transformation */
177  } else {
178  ptr->type = GROUP_TYPE_NEWS;
179  ptr->spooldir = spooldir; /* another global - sigh */
180  }
181 }
182 
183 
184 /*
185  * Decide how to handle a bogus groupname.
186  * If we process them interactively, create an empty active[] for this
187  * group and mark it bogus for display in the group selection page
188  * Otherwise, bogus groups are not displayed and are dealt with when newsrc
189  * is written.
190  */
191 t_bool
193  char *name) /* return value is always ignored */
194 {
195  struct t_group *ptr;
196 
198  return FALSE;
199 
200  if ((ptr = group_add(name)) == NULL)
201  return FALSE;
202 
204  ptr->bogus = TRUE; /* Mark it bogus */
205  /*
206  * Set pointer to default attributes
207  */
208  if (ptr->attribute && !ptr->attribute->global)
209  free(ptr->attribute);
210  ptr->attribute = scopes[0].attribute;
211 
212  if (my_group_add(name, FALSE) < 0)
213  return TRUE;
214 
215  return FALSE; /* Nothing was printed yet */
216 }
217 
218 
219 /*
220  * Parse line from news or mail active files
221  */
222 t_bool
224  char *line,
225  t_artnum *max,
226  t_artnum *min,
227  char *moderated)
228 {
229  char *p = NULL, *q = NULL, *r = NULL;
230  t_bool lineok = FALSE;
231 
232  if (line[0] == '#' || line[0] == '\0')
233  return FALSE;
234 
235  if (strtok(line, ACTIVE_SEP)) { /* skip group name */
236  if ((p = strtok(NULL, ACTIVE_SEP))) { /* group max count */
237  if ((q = strtok(NULL, ACTIVE_SEP))) { /* group min count */
238  r = strtok(NULL, ACTIVE_SEP); /* mod status or path to mailgroup */
239  lineok = TRUE;
240  }
241  }
242  }
243 
244  if (!p || !q || !r || !lineok) {
245 #ifdef DEBUG
246  /* TODO: This also logs broken non NNTP active lines (i.e. mail.active) to NNTP */
247  if (debug & DEBUG_NNTP && verbose > 1)
248  debug_print_file("NNTP", "Active file corrupt - %s", line);
249 #endif /* DEBUG */
250  return FALSE;
251  }
252 
253  *max = atoartnum(p);
254  *min = atoartnum(q);
255  strcpy(moderated, r);
256 
257  return TRUE;
258 }
259 
260 
261 #ifdef NNTP_ABLE
262 /*
263  * Parse line from "LIST COUNTS" (RFC 6048)
264  * group high low count status
265  */
266 static t_bool
267 parse_count_line(
268  char *line,
269  t_artnum *max,
270  t_artnum *min,
271  t_artnum *count,
272  char *moderated)
273 {
274  char *p = NULL, *q = NULL, *r = NULL, *s = NULL;
275  t_bool lineok = FALSE;
276 
277  if (line[0] == '#' || line[0] == '\0')
278  return FALSE;
279 
280  if (strtok(line, ACTIVE_SEP)) { /* skip group name */
281  if ((p = strtok(NULL, ACTIVE_SEP))) { /* group max */
282  if ((q = strtok(NULL, ACTIVE_SEP))) { /* group min */
283  if ((r = strtok(NULL, ACTIVE_SEP))) { /* group count */
284  s = strtok(NULL, ACTIVE_SEP); /* mod status or path to mailgroup */
285  lineok = TRUE;
286  }
287  }
288  }
289  }
290 
291  if (!p || !q || !r || !s || !lineok) {
292 # ifdef DEBUG
293  if (debug & DEBUG_NNTP && verbose > 1)
294  debug_print_file("NNTP", "unparsable \"LIST COUNTS\" line: \"%s\"", line);
295 # endif /* DEBUG */
296  return FALSE;
297  }
298 
299  *max = atoartnum(p);
300  *min = atoartnum(q);
301  *count = atoartnum(r);
302  strcpy(moderated, s);
303 
304  return TRUE;
305 }
306 #endif /* NNTP_ABLE */
307 
308 
309 /*
310  * Load the active information into active[] by counting the min/max/count
311  * for each news group.
312  * Parse a line from the .newsrc file
313  * Send GROUP command to NNTP server directly to keep window.
314  * We can't know the 'moderator' status and always return 'y'
315  * But we don't change if the 'moderator' status is already checked by
316  * read_active_file()
317  * Returns TRUE if NNTP is enabled and authentication is needed
318  */
319 #ifdef NNTP_ABLE
320 static t_bool
321 #else
322 static void
323 #endif /* NNTP_ABLE */
325  FILE *fp)
326 {
327  char *ptr;
328  char *p;
329  char moderated[PATH_LEN];
330  int window = 0;
331  long processed = 0L;
332  t_artnum count = T_ARTNUM_CONST(-1), min = T_ARTNUM_CONST(1), max = T_ARTNUM_CONST(0);
333  static char ngname[NNTP_GRPLEN + 1]; /* RFC 3977 3.1 limits group names to 497 octets */
334  struct t_group *grpptr;
335 #ifdef NNTP_ABLE
336  t_bool need_auth = FALSE;
337  char *ngnames[NUM_SIMULTANEOUS_GROUP_COMMAND];
338  int index_i = 0;
339  int index_o = 0;
340 #endif /* NNTP_ABLE */
341 
342  rewind(fp);
343 
344  if (!batch_mode || verbose)
346 
347  while ((ptr = tin_fgets(fp, FALSE)) != NULL || window != 0) {
348  if (ptr) {
349  p = strpbrk(ptr, ":!");
350 
351  if (!p || *p != SUBSCRIBED) /* Invalid line or unsubscribed */
352  continue;
353  *p = '\0'; /* Now ptr is the group name */
354 
355  /*
356  * 128 should be enough for a groupname, >256 and we overflow buffers
357  * later on
358  * TODO: check RFCs for possible max. size
359  */
360  my_strncpy(ngname, ptr, 128);
361  ptr = ngname;
362  }
363 
365 #ifdef NNTP_ABLE
366  char buf[NNTP_STRLEN];
367  char line[NNTP_STRLEN];
368 
369  if (window < NUM_SIMULTANEOUS_GROUP_COMMAND && ptr && (!list_active || (newsrc_active && list_active && group_find(ptr, FALSE)))) {
370  ngnames[index_i] = my_strdup(ptr);
371  snprintf(buf, sizeof(buf), "GROUP %s", ngnames[index_i]);
372 # ifdef DEBUG
373  if ((debug & DEBUG_NNTP) && verbose > 1)
374  debug_print_file("NNTP", "read_newsrc_active_file() %s", buf);
375 # endif /* DEBUG */
376  put_server(buf);
377  index_i = (index_i + 1) % NUM_SIMULTANEOUS_GROUP_COMMAND;
378  window++;
379  }
380  if (window == NUM_SIMULTANEOUS_GROUP_COMMAND || ptr == NULL) {
381  int respcode = get_only_respcode(line, sizeof(line));
382 
383  if (reconnected_in_last_get_server) {
384  /*
385  * If tin reconnected, last output is resended to server.
386  * So received data is for ngnames[last window_i].
387  * We resend all buffered command except for last window_i.
388  * And rotate buffer to use data received.
389  */
390  int i;
391  int j = index_o;
392  for (i = 0; i < window - 1; i++) {
393  snprintf(buf, sizeof(buf), "GROUP %s", ngnames[j]);
394 # ifdef DEBUG
395  if ((debug & DEBUG_NNTP) && verbose > 1)
396  debug_print_file("NNTP", "read_newsrc_active_file() %s", buf);
397 # endif /* DEBUG */
398  put_server(buf);
399  j = (j + 1) % NUM_SIMULTANEOUS_GROUP_COMMAND;
400  }
401  if (--index_o < 0)
402  index_o = NUM_SIMULTANEOUS_GROUP_COMMAND - 1;
403  if (--index_i < 0)
404  index_i = NUM_SIMULTANEOUS_GROUP_COMMAND - 1;
405  if (index_i != index_o)
406  ngnames[index_o] = ngnames[index_i];
407  }
408 
409  switch (respcode) {
410 
411  case OK_GROUP:
412  {
413  char fmt[25];
414 
415  snprintf(fmt, sizeof(fmt), "%%"T_ARTNUM_SFMT" %%"T_ARTNUM_SFMT" %%"T_ARTNUM_SFMT" %%%ds", NNTP_GRPLEN);
416  if (sscanf(line, fmt, &count, &min, &max, ngname) != 4) {
417 # ifdef DEBUG
418  if (debug & DEBUG_NNTP && verbose > 1)
419  debug_print_file("NNTP", "Invalid response to \"GROUP %s\": \"%s\"", ngnames[index_o], line);
420 # endif /* DEBUG */
421  }
422  if (strcmp(ngname, ngnames[index_o]) != 0) {
423 # ifdef DEBUG
424  if (debug & DEBUG_NNTP && verbose > 1)
425  debug_print_file("NNTP", "Groupname mismatch in response to \"GROUP %s\": \"%s\"", ngnames[index_o], line);
426 # endif /* DEBUG */
427  }
428  ptr = ngname;
429  free(ngnames[index_o]);
430  index_o = (index_o + 1) % NUM_SIMULTANEOUS_GROUP_COMMAND;
431  window--;
432  break;
433  }
434 
435  case ERR_NOAUTH:
436  case NEED_AUTHINFO:
437  need_auth = TRUE; /* delay auth till end of loop */
438  /* keep lint quiet: */
439  /* FALLTHROUGH */
440 
441  case ERR_NOGROUP:
442  free(ngnames[index_o]);
443  index_o = (index_o + 1) % NUM_SIMULTANEOUS_GROUP_COMMAND;
444  window--;
445  continue;
446 
447  case ERR_ACCESS:
448  tin_done(NNTP_ERROR_EXIT, "%s", line);
449  /* keep lint quiet: */
450  /* FALLTHROUGH */
451 
452  default:
453 # ifdef DEBUG
454  if ((debug & DEBUG_NNTP) && verbose > 1)
455  debug_print_file("NNTP", "NOT_OK %s", line);
456 # endif /* DEBUG */
457  free(ngnames[index_o]);
458  index_o = (index_o + 1) % NUM_SIMULTANEOUS_GROUP_COMMAND;
459  window--;
460  continue;
461  }
462  } else
463  continue;
464 #endif /* NNTP_ABLE */
465  } else {
466  if (group_get_art_info(spooldir, ptr, GROUP_TYPE_NEWS, &count, &max, &min))
467  continue;
468  }
469 
470  strcpy(moderated, "y");
471 
472  if (++processed % 5 == 0)
473  spin_cursor();
474 
475  /*
476  * Load group into group hash table
477  * NULL means group already present, so we just fixup the counters
478  * This call may implicitly ++num_active
479  */
480  if ((grpptr = group_add(ptr)) == NULL) {
481  t_bool changed = FALSE;
482 
483  if ((grpptr = group_find(ptr, FALSE)) == NULL)
484  continue;
485 
486  if (max > grpptr->xmax) {
487  grpptr->xmax = max;
488  changed = TRUE;
489  }
490  if (min > grpptr->xmin) {
491  grpptr->xmin = min;
492  changed = TRUE;
493  }
494  if (changed) {
495  grpptr->count = count;
496  expand_bitmap(grpptr, 0); /* TODO: expand_bitmap(grpptr,grpptr->xmin) should be enough */
497  }
498  continue;
499  }
500 
501  /*
502  * Load the new group in active[]
503  */
504  active_add(grpptr, count, max, min, moderated);
505  }
506 #ifdef NNTP_ABLE
507  return need_auth;
508 #endif /* NNTP_ABLE */
509 }
510 
511 
512 /*
513  * Wrapper for do_read_newsrc_active_file() to handle
514  * missing authentication
515  */
516 static void
518  void)
519 {
520  FILE *fp;
521 #ifdef NNTP_ABLE
522  t_bool need_auth;
523 #endif /* NNTP_ABLE */
524 
525  /*
526  * return immediately if no .newsrc can be found or .newsrc is empty
527  * when function asked to use .newsrc
528  */
529  if ((fp = fopen(newsrc, "r")) == NULL)
530  return;
531 
532  if (file_size(newsrc) <= 0L) {
533  fclose(fp);
534  return;
535  }
536 
537 #ifdef NNTP_ABLE
538  need_auth = do_read_newsrc_active_file(fp);
539 #else
541 #endif /* NNTP_ABLE */
542 
543 #ifdef NNTP_ABLE
544  if (need_auth) { /* delayed auth */
545  if (!authenticate(nntp_server, userid, FALSE) || do_read_newsrc_active_file(fp)) {
546  tin_done(EXIT_FAILURE, _(txt_auth_failed), ERR_ACCESS);
547  }
548  }
549 #endif /* NNTP_ABLE */
550 
551  fclose(fp);
552 
553  /*
554  * Exit if active file wasn't read correctly or is empty
555  */
556  if (tin_errno || !num_active) {
557  if (newsrc_active && !num_active)
559  else
561  }
562 
563  if (!batch_mode || verbose)
564  my_fputc('\n', stdout);
565 }
566 
567 
568 /*
569  * Open the news active file locally or send the LIST command
570  */
571 static FILE *
573  void)
574 {
575 #ifdef NNTP_ABLE
577  return (nntp_command("LIST", OK_GROUPS, NULL, 0));
578 #endif /* NNTP_ABLE */
579  return (fopen(news_active_file, "r"));
580 }
581 
582 
583 /*
584  * Load the active file into active[]
585  */
586 static void
588  void)
589 {
590  FILE *fp;
591  char *ptr;
592  char moderated[PATH_LEN];
593  long processed = 0L;
594  struct t_group *grpptr;
595  t_artnum count = T_ARTNUM_CONST(-1), min = T_ARTNUM_CONST(1), max = T_ARTNUM_CONST(0);
596 
597  if (!batch_mode || verbose)
599 
600  if ((fp = open_news_active_fp()) == NULL) {
601  if (cmd_line && !batch_mode)
602  my_fputc('\n', stderr);
603 
604 #ifdef NNTP_ABLE
605  if (read_news_via_nntp)
606  tin_done(EXIT_FAILURE, _(txt_cannot_retrieve), ACTIVE_FILE);
607 # ifndef NNTP_ONLY
608  else
609  tin_done(EXIT_FAILURE, _(txt_cannot_open_active_file), news_active_file, tin_progname);
610 # endif /* !NNTP_ONLY */
611 #else
613 #endif /* NNTP_ABLE */
614  }
615 
616  while ((ptr = tin_fgets(fp, FALSE)) != NULL) {
617 #if defined(DEBUG) && defined(NNTP_ABLE)
618  if ((debug & DEBUG_NNTP) && verbose) /* long multiline response */
619  debug_print_file("NNTP", "<<<%s%s", logtime(), ptr);
620 #endif /* DEBUG && NNTP_ABLE */
621 
622  if (!parse_active_line(ptr, &max, &min, moderated))
623  continue;
624 
625  if (++processed % MODULO_COUNT_NUM == 0)
626  spin_cursor();
627 
628  /*
629  * Load group into group hash table
630  * NULL means group already present, so we just fixup the counters
631  * This call may implicitly ++num_active
632  */
633  if ((grpptr = group_add(ptr)) == NULL) {
634  if ((grpptr = group_find(ptr, FALSE)) == NULL)
635  continue;
636 
637  if (max > grpptr->xmax) {
638  grpptr->xmax = max;
639  grpptr->count = count;
640  }
641 
642  if (min > grpptr->xmin) {
643  grpptr->xmin = min;
644  grpptr->count = count;
645  }
646 
647  continue;
648  }
649 
650  /*
651  * Load the new group in active[]
652  */
653  active_add(grpptr, count, max, min, moderated);
654  }
655 
656  TIN_FCLOSE(fp);
657 
658  /*
659  * Exit if active file wasn't read correctly or is empty
660  */
661  if (tin_errno || !num_active)
663 
664  if (!batch_mode || verbose)
665  my_fputc('\n', stdout);
666 }
667 
668 
669 #ifdef NNTP_ABLE
670 /*
671  * Load the active file into active[] via LIST COUNTS
672  */
673 static void
674 read_active_counts(
675  void)
676 {
677  FILE *fp;
678  char *ptr;
679  char moderated[PATH_LEN];
680  long processed = 0L;
681  struct t_group *grpptr;
682  t_artnum count = T_ARTNUM_CONST(-1), min = T_ARTNUM_CONST(1), max = T_ARTNUM_CONST(0);
683 
684  if (!batch_mode || verbose)
686 
687  if ((fp = nntp_command("LIST COUNTS", OK_GROUPS, NULL, 0)) == NULL) {
688  if (cmd_line && !batch_mode)
689  my_fputc('\n', stderr);
690 
691  tin_done(EXIT_FAILURE,_(txt_cannot_retrieve), ACTIVE_FILE);
692  }
693 
694  while ((ptr = tin_fgets(fp, FALSE)) != NULL) {
695 # ifdef DEBUG
696  if ((debug & DEBUG_NNTP) && verbose) /* long multiline response */
697  debug_print_file("NNTP", "<<<%s%s", logtime(), ptr);
698 # endif /* DEBUG */
699 
700  if (!parse_count_line(ptr, &max, &min, &count, moderated))
701  continue;
702 
703  if (++processed % MODULO_COUNT_NUM == 0)
704  spin_cursor();
705 
706  /*
707  * Load group into group hash table
708  * NULL means group already present, so we just fixup the counters
709  * This call may implicitly ++num_active
710  */
711  if ((grpptr = group_add(ptr)) == NULL) {
712  if ((grpptr = group_find(ptr, FALSE)) == NULL)
713  continue;
714 
715  if (max > grpptr->xmax) {
716  grpptr->xmax = max;
717  grpptr->count = count;
718  }
719 
720  if (min > grpptr->xmin) {
721  grpptr->xmin = min;
722  grpptr->count = count;
723  }
724 
725  continue;
726  }
727 
728  /*
729  * Load the new group in active[]
730  */
731  active_add(grpptr, count, max, min, moderated);
732  }
733 
734  /*
735  * Exit if active file wasn't read correctly or is empty
736  */
737  if (tin_errno || !num_active)
739 
740  if (!batch_mode || verbose)
741  my_fputc('\n', stdout);
742 }
743 #endif /* NNTP_ABLE */
744 
745 
746 /*
747  * Load the active file into active[]
748  * Check and preload any new newgroups into my_group[]
749  */
750 int
752  void)
753 {
754  FILE *fp;
755  int newgrps = 0;
756  t_bool do_group_cmds = !nntp_caps.list_counts;
757 #if defined(NNTP_ABLE) && !defined(DISABLE_PIPELINING)
758  t_bool did_list_cmd = FALSE;
759 #endif /* NNTP_ABLE && !DISABLE_PIPELINING */
760 
761  /*
762  * Ignore -n if no .newsrc can be found or .newsrc is empty
763  */
764  if (newsrc_active) {
765  if ((fp = fopen(newsrc, "r")) == NULL) {
766  list_active = TRUE;
768  } else {
769  fclose(fp);
770  if (file_size(newsrc) <= 0L) {
771  list_active = TRUE;
773  }
774  }
775  }
776 
777  /* Read an active file if it is allowed */
778  if (list_active) {
779 #ifdef NNTP_ABLE
780 # ifndef DISABLE_PIPELINING
781  did_list_cmd = TRUE;
782 # endif /* !DISABLE_PIPELINING */
784  read_active_counts();
785  else
786 #endif /* NNTP_ABLE */
788  }
789 
790  /* Read .newsrc and check each group */
791  if (newsrc_active) {
792 #ifdef NNTP_ABLE
793 # ifndef DISABLE_PIPELINING
794  /*
795  * prefer LIST COUNTS, otherwise use LIST ACTIVE (-l) or GROUP (-n)
796  * or both (-ln); LIST COUNTS/ACTIVE grplist is used up to
797  * PIPELINE_LIMIT groups in newsrc
798  */
799  if (read_news_via_nntp && (list_active || nntp_caps.list_counts) && !did_list_cmd) {
800  char buff[NNTP_STRLEN];
801  char *ptr, *q;
802  char moderated[PATH_LEN];
803  int r = 0, j = 0;
804  int i;
805  struct t_group *grpptr;
806  t_artnum count = T_ARTNUM_CONST(-1), min = T_ARTNUM_CONST(1), max = T_ARTNUM_CONST(0);
807  t_bool need_auth = FALSE;
808 
809  *buff = '\0';
810  /* we can't use for_each_group(i) yet, so we have to parse the newsrc */
811  if ((fp = fopen(newsrc, "r")) != NULL) {
812  while (tin_fgets(fp, FALSE) != NULL)
813  j++;
814  rewind(fp);
815  if (j < PIPELINE_LIMIT) {
816  while ((ptr = tin_fgets(fp, FALSE)) != NULL) {
817  if (!(q = strpbrk(ptr, ":!")))
818  continue;
819  *q = '\0';
821  /* LIST ACTIVE or LIST COUNTS takes wildmats */
822  if (*buff && ((strlen(buff) + strlen(ptr)) < (NNTP_GRPLEN - 1))) { /* append group name */
823  snprintf(buff + strlen(buff), sizeof(buff) - strlen(buff), ",%s", ptr);
824  } else {
825  if (*buff) {
826  put_server(buff);
827  r++;
828  }
829  snprintf(buff, sizeof(buff), "LIST %s %s", nntp_caps.list_counts ? "COUNTS" : "ACTIVE", ptr);
830  }
831  continue;
832  } else
833  snprintf(buff, sizeof(buff), "LIST ACTIVE %s", ptr);
834  put_server(buff);
835  r++;
836  *buff = '\0';
837  }
838  if (*buff) {
839  put_server(buff);
840  r++;
841  }
842  } else {
843  do_group_cmds = TRUE;
844  }
845  fclose(fp);
846 
847  if (j < PIPELINE_LIMIT) {
848  for (i = 0; i < r && !did_reconnect; i++) {
849  if ((j = get_only_respcode(buff, sizeof(buff))) != OK_GROUPS) {
850  /* TODO: add 483 (RFC 3977) code */
851  if (j == ERR_NOAUTH || j == NEED_AUTHINFO)
852  need_auth = TRUE;
853 #if 0 /* do we need something like this? */
854  if (j == ERR_CMDSYN)
855  list_active = TRUE;
856 #endif /* 0 */
857  continue;
858  } else {
859  while ((ptr = tin_fgets(FAKE_NNTP_FP, FALSE)) != NULL) {
860 # ifdef DEBUG
861  if ((debug & DEBUG_NNTP) && verbose) /* long multiline response */
862  debug_print_file("NNTP", "<<<%s%s", logtime(), ptr);
863 # endif /* DEBUG */
865  if (!parse_count_line(ptr, &max, &min, &count, moderated))
866  continue;
867  } else {
868  if (!parse_active_line(ptr, &max, &min, moderated))
869  continue;
870  }
871 
872  if ((grpptr = group_add(ptr)) == NULL) {
873  if ((grpptr = group_find(ptr, FALSE)) == NULL)
874  continue;
875 
876  if (max > grpptr->xmax) {
877  grpptr->xmax = max;
878  grpptr->count = count;
879  }
880  if (min > grpptr->xmin) {
881  grpptr->xmin = min;
882  grpptr->count = count;
883  }
884  continue;
885  }
886  active_add(grpptr, count, max, min, moderated);
887  }
888  }
889  }
890  if (need_auth) { /* retry after auth is overkill here, so just auth */
891  if (!authenticate(nntp_server, userid, FALSE))
893  }
894  }
895  did_reconnect = FALSE;
896  }
897  }
898 # endif /* !DISABLE_PIPELINING */
899 #endif /* NNTP_ABLE */
900  if (!nntp_caps.list_counts || do_group_cmds)
902  }
903 
904  (void) time(&active_timestamp);
906 
907  /*
908  * check_for_any_new_groups() also does $AUTOSUBSCRIBE
909  */
911  newgrps = check_for_any_new_groups();
912 
913  /*
914  * finally we have a list of all groups and can set the attributes
915  */
917 
918  return newgrps;
919 }
920 
921 
922 /*
923  * Open the active.times file locally or send the NEWGROUPS command
924  * "NEWGROUPS yymmdd hhmmss"
925  */
926 static FILE *
928  int idx)
929 {
930 #ifdef NNTP_ABLE
931  char line[NNTP_STRLEN];
932  struct tm *ngtm;
933 
935  /*
936  * not checking for caps_type == CAPABILITIES && reader as some
937  * servers do not support it even if advertizing READER so we must
938  * handle errors anyway and just issue the cmd.
939  */
940  if (idx == -1 || ((ngtm = localtime(&newnews[idx].time)) == NULL))
941  return (FILE *) 0;
942 
943  /*
944  * RFC 3077 states that we SHOULD use 4 digit year but some servers
945  * still do not support it.
946  */
947  snprintf(line, sizeof(line), "NEWGROUPS %02d%02d%02d %02d%02d%02d",
948  ngtm->tm_year % 100, ngtm->tm_mon + 1, ngtm->tm_mday,
949  ngtm->tm_hour, ngtm->tm_min, ngtm->tm_sec);
950 
951  return (nntp_command(line, OK_NEWGROUPS, NULL, 0));
952  }
953 #endif /* NNTP_ABLE */
954  return (fopen(active_times_file, "r"));
955 }
956 
957 
958 /*
959  * Check for any newly created newsgroups.
960  *
961  * If reading news locally check the NEWSLIBDIR/active.times file.
962  * Format: Groupname Seconds Creator
963  *
964  * If reading news via NNTP issue a NEWGROUPS command.
965  * Format: (as active file) Groupname Maxart Minart moderated
966  */
967 static int
969  void)
970 {
971  FILE *fp;
972  char *autosubscribe, *autounsubscribe;
973  char *ptr, *line, buf[NNTP_STRLEN];
974  char old_newnews_host[PATH_LEN];
975  int newnews_index;
976  int newgrps = 0;
977  time_t old_newnews_time;
978  time_t new_newnews_time;
979 
980  if (!batch_mode /* || verbose */)
982 
983  (void) time(&new_newnews_time);
984 
985  /*
986  * find out if we have read news from here before otherwise -1
987  */
988  if ((newnews_index = find_newnews_index(nntp_server)) >= 0) {
989  STRCPY(old_newnews_host, newnews[newnews_index].host);
990  old_newnews_time = newnews[newnews_index].time;
991  } else {
992  STRCPY(old_newnews_host, "UNKNOWN");
993  old_newnews_time = (time_t) 0;
994  }
995 
996 #ifdef DEBUG
997  if ((debug & DEBUG_NNTP) && verbose > 1)
998  debug_print_file("NNTP", "Newnews old=[%lu] new=[%lu]", (unsigned long int) old_newnews_time, (unsigned long int) new_newnews_time);
999 #endif /* DEBUG */
1000 
1001  if ((fp = open_newgroups_fp(newnews_index)) != NULL) {
1002  /*
1003  * Need these later. They list user-defined groups to be
1004  * automatically subscribed or unsubscribed.
1005  */
1006  autosubscribe = getenv("AUTOSUBSCRIBE");
1007  autounsubscribe = getenv("AUTOUNSUBSCRIBE");
1008 
1009  while ((line = tin_fgets(fp, FALSE)) != NULL) {
1010  /*
1011  * Split the group name off and subscribe. If we're reading local,
1012  * we must check the creation date manually
1013  */
1014  if ((ptr = strchr(line, ' ')) != NULL) {
1015  if (!read_news_via_nntp && ((time_t) atol(ptr) < old_newnews_time || old_newnews_time == (time_t) 0))
1016  continue;
1017 
1018  *ptr = '\0';
1019  }
1020  subscribe_new_group(line, autosubscribe, autounsubscribe);
1021  newgrps++;
1022  }
1023  TIN_FCLOSE(fp);
1024 
1025  if (tin_errno)
1026  return 0; /* Don't update the time if we quit */
1027  }
1028 
1029  /*
1030  * Update (if already existing) or create (if new) the in-memory
1031  * 'last time newgroups checked' slot for this server. It will be written
1032  * out as part of tinrc.
1033  */
1034  if (newnews_index >= 0)
1035  newnews[newnews_index].time = new_newnews_time;
1036  else {
1037  snprintf(buf, sizeof(buf), "%s %lu", nntp_server, (unsigned long int) new_newnews_time);
1039  }
1040 
1041  if (!batch_mode)
1042  my_fputc('\n', stdout);
1043 
1044  return newgrps;
1045 }
1046 
1047 
1048 /*
1049  * Subscribe to a new news group:
1050  * Handle the AUTOSUBSCRIBE/AUTOUNSUBSCRIBE env vars
1051  * They hold a wildcard list of groups that should be automatically
1052  * (un)subscribed when a new group is found
1053  * If a group is autounsubscribed, completely ignore it
1054  * If a group is autosubscribed, subscribe to it
1055  * Otherwise, mark it as New for inclusion in selection screen
1056  */
1057 static void
1059  char *group,
1060  char *autosubscribe,
1061  char *autounsubscribe)
1062 {
1063  int idx;
1064  struct t_group *ptr;
1065 
1066  /*
1067  * If we explicitly don't auto subscribe to this group, then don't bother going on
1068  */
1069  if ((autounsubscribe != NULL) && match_group_list(group, autounsubscribe))
1070  return;
1071 
1072  /*
1073  * Try to add the group to our selection list. If this fails, we're
1074  * probably using -n, so we fake an entry with no counts. The count will
1075  * be properly updated when we enter the group. Otherwise there is some
1076  * mismatch in the active.times data and we ignore the newgroup.
1077  */
1078  if ((idx = my_group_add(group, FALSE)) < 0) {
1079  if (list_active) {
1080 /* my_fprintf(stderr, "subscribe_new_group: %s not in active[] && list_active\n", group); */
1081  return;
1082  }
1083 
1084  if ((ptr = group_add(group)) != NULL)
1086 
1087  if ((idx = my_group_add(group, FALSE)) < 0)
1088  return;
1089  }
1090 
1091  if (!no_write && (autosubscribe != NULL) && match_group_list(group, autosubscribe)) {
1092  if (!batch_mode || verbose)
1093  my_printf(_(txt_autosubscribed), group);
1094 
1095  /*
1096  * as subscribe_new_group() is called from check_for_any_new_groups()
1097  * which has pending data on the socket if reading via NNTP we are not
1098  * allowed to issue any NNTP commands yet
1099  */
1101  /*
1102  * Bad kluge to stop group later appearing in New newsgroups. This
1103  * effectively loses the group, and it has now been subscribed to and
1104  * so will be reread later by read_newsrc()
1105  */
1106  selmenu.max--;
1107  } else
1108  active[my_group[idx]].newgroup = TRUE;
1109 }
1110 
1111 
1112 /*
1113  * See if group is a member of group_list, returning a boolean.
1114  * group_list is a comma separated list of newsgroups, ! implies NOT
1115  * The same degree of wildcarding as used elsewhere in tin is allowed
1116  */
1117 t_bool
1119  const char *group,
1120  const char *group_list)
1121 {
1122  char *separator;
1123  char pattern[HEADER_LEN];
1124  size_t group_len, list_len;
1125  t_bool negate, accept = FALSE;
1126 
1127  list_len = strlen(group_list);
1128  /*
1129  * walk through comma-separated entries in list
1130  */
1131  while (list_len != 0) {
1132  /*
1133  * find end/length of this entry
1134  */
1135  separator = strchr(group_list, ',');
1136  group_len = MIN(((separator == NULL) ? list_len : (size_t) (separator - group_list)), sizeof(pattern) - 1);
1137 
1138  if ((negate = (*group_list == '!'))) {
1139  /*
1140  * a '!' before the pattern inverts sense of match
1141  */
1142  group_list++;
1143  group_len--;
1144  list_len--;
1145  }
1146  /*
1147  * copy out the entry and terminate it properly
1148  */
1149  strncpy(pattern, group_list, group_len);
1150  pattern[group_len] = '\0';
1151  /*
1152  * case-insensitive wildcard match
1153  */
1154  if (GROUP_MATCH(group, pattern, TRUE))
1155  accept = bool_not(negate); /* matched! */
1156 
1157  /*
1158  * now examine next entry if any
1159  */
1160  if (group_list[group_len] != '\0')
1161  group_len++; /* skip the separator */
1162 
1163  group_list += group_len;
1164  list_len -= group_len;
1165  }
1166  return accept;
1167 }
1168 
1169 
1170 /*
1171  * Add or update an entry to the in-memory newnews[] array (The times newgroups
1172  * were last checked for a particular news server)
1173  * If this is first time we've been called, zero out the array.
1174  *
1175  * Side effects:
1176  * 'info' is modified. Caller should not depend on it.
1177  */
1178 void
1180  char *info)
1181 {
1182  char *ptr;
1183  int i;
1184  time_t new_time;
1185 
1186  /*
1187  * initialize newnews[] if no entries
1188  */
1189  if (!num_newnews) {
1190  for (i = 0; i < max_newnews; i++) {
1191  newnews[i].host = NULL;
1192  newnews[i].time = (time_t) 0;
1193  }
1194  }
1195 
1196  /*
1197  * Split 'info' into hostname and time
1198  */
1199  if ((ptr = strchr(info, ' ')) == NULL)
1200  return;
1201 
1202  *ptr++ = '\0';
1203  new_time = (time_t) atol(ptr);
1204 
1205  /*
1206  * If this is a new host entry, set it up
1207  */
1208  if ((i = find_newnews_index(info)) == -1) {
1209  i = num_newnews++;
1210 
1211  if (i >= max_newnews)
1212  expand_newnews();
1213  newnews[i].host = my_strdup(info);
1214  }
1215 
1216  newnews[i].time = new_time;
1217 
1218 #ifdef DEBUG
1219  if ((debug & DEBUG_NNTP) && verbose > 1)
1220  debug_print_file("NNTP", "ACTIVE host=[%s] time=[%lu]", newnews[i].host, (unsigned long int) newnews[i].time);
1221 #endif /* DEBUG */
1222 }
1223 
1224 
1225 /*
1226  * Return the index of cur_newnews_host in newnews[] or -1 if not found
1227  */
1228 int
1230  const char *cur_newnews_host)
1231 {
1232  int i;
1233 
1234  for (i = 0; i < num_newnews; i++) {
1235  if (STRCMPEQ(cur_newnews_host, newnews[i].host))
1236  return i;
1237  }
1238 
1239  return -1;
1240 }
1241 
1242 
1243 /*
1244  * Get a single status char from the moderated field. Used on selection screen
1245  * and in header of group screen
1246  */
1247 char
1249  char ch)
1250 {
1251  switch (ch) {
1252  case 'm':
1253  return 'M';
1254 
1255  case 'x':
1256  case 'n':
1257  case 'j':
1258  return 'X';
1259 
1260  case '=':
1261  return '=';
1262 
1263  default:
1264  return ' ';
1265  }
1266 }
1267 
1268 
1269 /* ex actived.c functions */
1270 void
1272  void)
1273 {
1274  char *fb;
1275  char group_path[PATH_LEN];
1276  char local_save_active_file[PATH_LEN];
1277 
1278  joinpath(local_save_active_file, sizeof(local_save_active_file), rcdir, ACTIVE_SAVE_FILE);
1279 
1280  if (no_write && file_size(local_save_active_file) != -1L)
1281  return;
1282 
1283  if (strfpath((cmdline.args & CMDLINE_SAVEDIR) ? cmdline.savedir : tinrc.savedir, group_path, sizeof(group_path), NULL, FALSE)) {
1285  print_active_head(local_save_active_file);
1286 
1287  while (strlen(group_path) && group_path[strlen(group_path) - 1] == '/')
1288  group_path[strlen(group_path) - 1] = '\0';
1289 
1290  fb = my_strdup(group_path);
1291  make_group_list(local_save_active_file, (cmdline.args & CMDLINE_SAVEDIR) ? cmdline.savedir : tinrc.savedir, fb, group_path);
1292  free(fb);
1293  }
1294 }
1295 
1296 
1297 static void
1299  char *active_file,
1300  char *base_dir,
1301  char *fixed_base,
1302  char *group_path)
1303 {
1304  DIR *dir;
1305  DIR_BUF *direntry;
1306  char *ptr;
1307  char filename[PATH_LEN];
1308  char path[PATH_LEN];
1309  t_artnum art_max;
1310  t_artnum art_min;
1311  struct stat stat_info;
1312  t_bool is_dir;
1313 
1314  if ((dir = opendir(group_path)) != NULL) {
1315  is_dir = FALSE;
1316  while ((direntry = readdir(dir)) != NULL) {
1317  STRCPY(filename, direntry->d_name);
1318  joinpath(path, sizeof(path), group_path, filename);
1319  if (!(filename[0] == '.' && filename[1] == '\0') &&
1320  !(filename[0] == '.' && filename[1] == '.' && filename[2] == '\0')) {
1321  if (stat(path, &stat_info) != -1) {
1322  if (S_ISDIR(stat_info.st_mode))
1323  is_dir = TRUE;
1324  }
1325  }
1326  if (is_dir) {
1327  is_dir = FALSE;
1328  strcpy(group_path, path);
1329 
1330  make_group_list(active_file, base_dir, fixed_base, group_path);
1331  find_art_max_min(group_path, &art_max, &art_min);
1332  append_group_line(active_file, group_path + strlen(fixed_base) + 1, art_max, art_min, fixed_base);
1333  if ((ptr = strrchr(group_path, '/')) != NULL)
1334  *ptr = '\0';
1335  }
1336  }
1337  CLOSEDIR(dir);
1338  }
1339 }
1340 
1341 
1342 static void
1344  char *active_file,
1345  char *group_path,
1346  t_artnum art_max,
1347  t_artnum art_min,
1348  char *base_dir)
1349 {
1350  FILE *fp;
1351  char *file_tmp;
1352 
1353  if (art_max == 0 && art_min == 1)
1354  return;
1355 
1356  file_tmp = get_tmpfilename(active_file);
1357 
1358  if (!backup_file(active_file, file_tmp)) {
1359  free(file_tmp);
1360  return;
1361  }
1362 
1363  if ((fp = fopen(active_file, "a+")) != NULL) {
1364  char *ptr;
1365  char *group_name;
1366  int err;
1367 
1368  ptr = group_name = my_strdup(group_path);
1369  ptr++;
1370  while ((ptr = strchr(ptr, '/')) != NULL)
1371  *ptr = '.';
1372 
1373  wait_message(0, "Appending=[%s %"T_ARTNUM_PFMT" %"T_ARTNUM_PFMT" %s]\n", group_name, art_max, art_min, base_dir);
1374  print_group_line(fp, group_name, art_max, art_min, base_dir);
1375  if ((err = ferror(fp)) || fclose(fp)) { /* TODO: issue warning? */
1376  if (err) {
1377  clearerr(fp);
1378  fclose(fp);
1379  }
1380  err = rename(file_tmp, active_file);
1381 #ifdef DEBUG
1382  if ((debug & DEBUG_MISC) && err) /* TODO: is this the right debug-level? */
1383  perror_message(_(txt_rename_error), file_tmp, active_file);
1384 #endif /* DEBUG */
1385  }
1386  free(group_name);
1387  }
1388  unlink(file_tmp);
1389  free(file_tmp);
1390 }
name
const char * name
Definition: signal.c:117
DEBUG_NNTP
#define DEBUG_NNTP
Definition: debug.h:47
backup_file
t_bool backup_file(const char *filename, const char *backupname)
Definition: misc.c:213
txt_reading_news_active_file
constext txt_reading_news_active_file[]
Definition: lang.c:767
NNTP_STRLEN
#define NNTP_STRLEN
Definition: nntplib.h:155
read_newsrc_active_file
static void read_newsrc_active_file(void)
Definition: active.c:517
CAPABILITIES
@ CAPABILITIES
Definition: nntplib.h:171
DEBUG_MISC
#define DEBUG_MISC
Definition: debug.h:54
_
#define _(Text)
Definition: tin.h:94
OK_NEWGROUPS
#define OK_NEWGROUPS
Definition: nntplib.h:108
my_strdup
char * my_strdup(const char *str)
Definition: string.c:133
t_group
Definition: tin.h:1772
read_news_active_file
int read_news_active_file(void)
Definition: active.c:751
open_news_active_fp
static FILE * open_news_active_fp(void)
Definition: active.c:572
t_capabilities::list_active
t_bool list_active
Definition: nntplib.h:192
ERR_AUTHFAIL
#define ERR_AUTHFAIL
Definition: nntplib.h:140
t_capabilities::type
enum extension_type type
Definition: nntplib.h:187
GROUP_TYPE_NEWS
#define GROUP_TYPE_NEWS
Definition: tin.h:1059
t_config::strip_bogus
int strip_bogus
Definition: tinrc.h:151
PIPELINE_LIMIT
#define PIPELINE_LIMIT
Definition: tin.h:2456
read_news_via_nntp
t_bool read_news_via_nntp
Definition: init.c:150
check_for_new_newsgroups
t_bool check_for_new_newsgroups
Definition: init.c:127
create_save_active_file
void create_save_active_file(void)
Definition: active.c:1271
expand_newnews
void expand_newnews(void)
Definition: memory.c:196
newnews
struct t_newnews * newnews
Definition: memory.c:68
active_add
static void active_add(struct t_group *ptr, t_artnum count, t_artnum max, t_artnum min, const char *moderated)
Definition: active.c:146
glob_filter
struct t_filters glob_filter
Definition: filter.c:87
process_bogus
t_bool process_bogus(char *name)
Definition: active.c:192
toggle_my_groups
void toggle_my_groups(const char *group)
Definition: select.c:1254
tinrc
struct t_config tinrc
Definition: init.c:191
perror_message
void perror_message(const char *fmt,...)
Definition: screen.c:220
need_reread_active_file
t_bool need_reread_active_file(void)
Definition: active.c:88
wait_message
void wait_message(unsigned int sdelay, const char *fmt,...)
Definition: screen.c:133
parse_active_line
t_bool parse_active_line(char *line, t_artnum *max, t_artnum *min, char *moderated)
Definition: active.c:223
expand_bitmap
void expand_bitmap(struct t_group *group, t_artnum min)
Definition: newsrc.c:1428
read_saved_news
t_bool read_saved_news
Definition: init.c:151
t_group::xmin
t_artnum xmin
Definition: tin.h:1780
OK_GROUPS
#define OK_GROUPS
Definition: nntplib.h:96
txt_servers_active
constext txt_servers_active[]
Definition: lang.c:842
MIN
#define MIN(a, b)
Definition: tin.h:805
read_active_file
static void read_active_file(void)
Definition: active.c:587
my_fputc
#define my_fputc(ch, stream)
Definition: tcurses.h:152
group_get_art_info
int group_get_art_info(char *tin_spooldir, char *groupname, int grouptype, t_artnum *art_count, t_artnum *art_max, t_artnum *art_min)
Definition: newsrc.c:407
t_capabilities::list_counts
t_bool list_counts
Definition: nntplib.h:204
CLOSEDIR
#define CLOSEDIR(DIR)
Definition: tin.h:2355
t_group::type
unsigned int type
Definition: tin.h:1781
tcurses.h
assign_attributes_to_groups
void assign_attributes_to_groups(void)
Definition: attrib.c:973
TIN_FCLOSE
#define TIN_FCLOSE(x)
Definition: tin.h:1037
t_menu::max
int max
Definition: tin.h:2007
t_attribute
Definition: tin.h:1564
do_read_newsrc_active_file
static void do_read_newsrc_active_file(FILE *fp)
Definition: active.c:324
tin.h
tin_done
void tin_done(int ret, const char *fmt,...)
Definition: misc.c:557
CMDLINE_SAVEDIR
#define CMDLINE_SAVEDIR
Definition: tin.h:1094
resync_active_file
t_bool resync_active_file(void)
Definition: active.c:102
max_newnews
int max_newnews
Definition: memory.c:52
txt_autosubscribed
constext txt_autosubscribed[]
Definition: lang.c:106
set_default_bitmap
void set_default_bitmap(struct t_group *group)
Definition: newsrc.c:1636
check_for_any_new_groups
static int check_for_any_new_groups(void)
Definition: active.c:968
cmdline
struct t_cmdlineopts cmdline
Definition: init.c:189
t_newnews::time
time_t time
Definition: tin.h:1965
ERR_CMDSYN
#define ERR_CMDSYN
Definition: nntplib.h:145
PATH_LEN
#define PATH_LEN
Definition: tin.h:837
group_find
struct t_group * group_find(const char *group_name, t_bool ignore_case)
Definition: list.c:154
rcdir
char rcdir[PATH_LEN]
Definition: init.c:100
tin_progname
char * tin_progname
Definition: init.c:105
atol
long atol(const char *s)
Definition: string.c:385
active
struct t_group * active
Definition: memory.c:66
tin_fgets
char * tin_fgets(FILE *fp, t_bool header)
Definition: read.c:320
subscribe_new_group
static void subscribe_new_group(char *group, char *autosubscribe, char *autounsubscribe)
Definition: active.c:1058
STRCMPEQ
#define STRCMPEQ(s1, s2)
Definition: tin.h:816
print_group_line
void print_group_line(FILE *fp, const char *group_name, t_artnum art_max, t_artnum art_min, const char *base_dir)
Definition: mail.c:578
GROUP_TYPE_SAVE
#define GROUP_TYPE_SAVE
Definition: tin.h:1060
t_newnews::host
char * host
Definition: tin.h:1964
my_strncpy
void my_strncpy(char *p, const char *q, size_t n)
Definition: string.c:190
T_ARTNUM_PFMT
#define T_ARTNUM_PFMT
Definition: tin.h:227
group_flag
char group_flag(char ch)
Definition: active.c:1248
show_selection_page
void show_selection_page(void)
Definition: select.c:578
file_size
long file_size(const char *file)
Definition: misc.c:2122
ACTIVE_SEP
#define ACTIVE_SEP
Definition: active.c:52
t_newsrc::xbitmap
t_bitmap * xbitmap
Definition: tin.h:1766
nntp_caps
struct t_capabilities nntp_caps
Definition: init.c:516
GROUP_MATCH
#define GROUP_MATCH(s1, pat, case_s)
Definition: tin.h:1014
get_tmpfilename
char * get_tmpfilename(const char *filename)
Definition: misc.c:101
read_cmd_line_groups
int read_cmd_line_groups(void)
Definition: main.c:987
append_group_line
static void append_group_line(char *active_file, char *group_path, t_artnum art_max, t_artnum art_min, char *base_dir)
Definition: active.c:1343
t_group::description
char * description
Definition: tin.h:1775
strfpath
int strfpath(const char *format, char *str, size_t maxsize, struct t_group *group, t_bool expand_all)
Definition: misc.c:1701
cmd_line
t_bool cmd_line
Definition: init.c:128
buf
static char buf[16]
Definition: langinfo.c:50
t_attribute::global
unsigned global
Definition: tin.h:1596
open_newgroups_fp
static FILE * open_newgroups_fp(int idx)
Definition: active.c:927
ERR_NOGROUP
#define ERR_NOGROUP
Definition: nntplib.h:126
FreeIfNeeded
#define FreeIfNeeded(p)
Definition: tin.h:2203
txt_rename_error
constext txt_rename_error[]
Definition: lang.c:777
t_group::moderated
char moderated
Definition: tin.h:1777
list_active
t_bool list_active
Definition: init.c:142
read_newsrc
signed long int read_newsrc(char *newsrc_file, t_bool allgroups)
Definition: newsrc.c:83
find_art_max_min
void find_art_max_min(const char *group_path, t_artnum *art_max, t_artnum *art_min)
Definition: mail.c:547
print_active_head
void print_active_head(const char *active_file)
Definition: mail.c:531
T_ARTNUM_CONST
#define T_ARTNUM_CONST(v)
Definition: tin.h:229
t_cmdlineopts::savedir
char savedir[255]
Definition: tin.h:1470
write_newsrc
signed long int write_newsrc(void)
Definition: newsrc.c:197
t_scope::attribute
struct t_attribute * attribute
Definition: tin.h:1752
NEED_AUTHINFO
#define NEED_AUTHINFO
Definition: nntplib.h:119
FAKE_NNTP_FP
#define FAKE_NNTP_FP
Definition: tin.h:455
atoartnum
#define atoartnum
Definition: tin.h:230
make_group_list
static void make_group_list(char *active_file, char *base_dir, char *fixed_base, char *group_path)
Definition: active.c:1298
EXIT_FAILURE
#define EXIT_FAILURE
Definition: tin.h:1277
ERR_ACCESS
#define ERR_ACCESS
Definition: nntplib.h:146
S_ISDIR
#define S_ISDIR(m)
Definition: tin.h:2127
scopes
struct t_scope * scopes
Definition: memory.c:67
active_times_file
char active_times_file[PATH_LEN]
Definition: init.c:66
group_add
struct t_group * group_add(const char *group)
Definition: list.c:213
bool_not
#define bool_not(b)
Definition: bool.h:81
t_group::xmax
t_artnum xmax
Definition: tin.h:1779
t_group::inrange
t_bool inrange
Definition: tin.h:1782
batch_mode
t_bool batch_mode
Definition: init.c:126
my_printf
#define my_printf
Definition: tcurses.h:169
txt_creating_active
constext txt_creating_active[]
Definition: lang.c:158
t_group::bogus
t_bool bogus
Definition: tin.h:1787
NNTP_ERROR_EXIT
#define NNTP_ERROR_EXIT
Definition: tin.h:1281
t_bitmap
unsigned char t_bitmap
Definition: tin.h:1450
t_cmdlineopts::args
unsigned int args
Definition: tin.h:1471
t_menu::curr
int curr
Definition: tin.h:2006
t_config::reread_active_file_secs
int reread_active_file_secs
Definition: tinrc.h:143
t_config::savedir
char savedir[PATH_LEN]
Definition: tinrc.h:126
t_group::newsrc
struct t_newsrc newsrc
Definition: tin.h:1789
t_group::art_was_posted
t_bool art_was_posted
Definition: tin.h:1784
txt_checking_new_groups
constext txt_checking_new_groups[]
Definition: lang.c:143
t_group::count
t_artnum count
Definition: tin.h:1778
FALSE
#define FALSE
Definition: bool.h:70
txt_cannot_open
constext txt_cannot_open[]
Definition: lang.c:128
STRCPY
#define STRCPY(dst, src)
Definition: tin.h:814
txt_active_file_is_empty
constext txt_active_file_is_empty[]
Definition: lang.c:49
debug
unsigned short debug
Definition: debug.c:51
verbose
int verbose
Definition: init.c:153
active_timestamp
static time_t active_timestamp
Definition: active.c:63
no_write
t_bool no_write
Definition: init.c:144
joinpath
void joinpath(char *result, size_t result_size, const char *dir, const char *file)
Definition: joinpath.c:50
newsrc_active
t_bool newsrc_active
Definition: init.c:143
newsrc
char newsrc[PATH_LEN]
Definition: init.c:96
snprintf
#define snprintf
Definition: tin.h:2417
my_group
int * my_group
Definition: memory.c:64
t_artnum
long t_artnum
Definition: tin.h:226
t_group::spooldir
char * spooldir
Definition: tin.h:1776
txt_reading_news_newsrc_file
constext txt_reading_news_newsrc_file[]
Definition: lang.c:768
t_group::attribute
struct t_attribute * attribute
Definition: tin.h:1790
ACTIVE_SAVE_FILE
#define ACTIVE_SAVE_FILE
Definition: tin.h:626
subscribe
void subscribe(struct t_group *group, int sub_state, t_bool get_info)
Definition: newsrc.c:537
t_group::glob_filter
struct t_filters * glob_filter
Definition: tin.h:1791
BOGUS_SHOW
#define BOGUS_SHOW
Definition: tin.h:1200
t_config::show_only_unread_groups
t_bool show_only_unread_groups
Definition: tinrc.h:233
spooldir
char spooldir[PATH_LEN]
Definition: init.c:102
MODULO_COUNT_NUM
#define MODULO_COUNT_NUM
Definition: tin.h:862
t_group::next
int next
Definition: tin.h:1788
userid
char userid[PATH_LEN]
Definition: init.c:107
selmenu
t_menu selmenu
Definition: select.c:85
load_newnews_info
void load_newnews_info(char *info)
Definition: active.c:1179
DIR_BUF
#define DIR_BUF
Definition: tin.h:380
OK_GROUP
#define OK_GROUP
Definition: nntplib.h:95
CURR_GROUP
#define CURR_GROUP
Definition: tin.h:1043
t_bool
unsigned t_bool
Definition: bool.h:77
reread_active_for_posted_arts
t_bool reread_active_for_posted_arts
Definition: init.c:148
num_newnews
int num_newnews
Definition: memory.c:53
t_group::read_during_session
t_bool read_during_session
Definition: tin.h:1783
ACTIVE_FILE
#define ACTIVE_FILE
Definition: tin.h:624
TRUE
#define TRUE
Definition: bool.h:74
find_newnews_index
int find_newnews_index(const char *cur_newnews_host)
Definition: active.c:1229
tin_errno
int tin_errno
Definition: read.c:59
HEADER_LEN
#define HEADER_LEN
Definition: tin.h:857
news_active_file
char news_active_file[PATH_LEN]
Definition: init.c:94
nntp_server
char * nntp_server
Definition: nntplib.c:28
t_group::subscribed
t_bool subscribed
Definition: tin.h:1785
t_group::aliasedto
char * aliasedto
Definition: tin.h:1774
SUBSCRIBED
#define SUBSCRIBED
Definition: tin.h:1341
txt_error_server_has_no_listed_groups
constext txt_error_server_has_no_listed_groups[]
Definition: lang.c:264
ERR_NOAUTH
#define ERR_NOAUTH
Definition: nntplib.h:139
NNTP_GRPLEN
#define NNTP_GRPLEN
Definition: nntplib.h:159
unlink
#define unlink(file)
Definition: tin.h:384
t_group::newgroup
t_bool newgroup
Definition: tin.h:1786
num_active
int num_active
Definition: memory.c:51
strpbrk
char * strpbrk(const char *str1, const char *str2)
Definition: string.c:305
T_ARTNUM_SFMT
#define T_ARTNUM_SFMT
Definition: tin.h:228
my_group_add
#define my_group_add(x, y)
Definition: tin.h:2209
spin_cursor
void spin_cursor(void)
Definition: screen.c:445
force_reread_active_file
t_bool force_reread_active_file
Definition: active.c:62
match_group_list
t_bool match_group_list(const char *group, const char *group_list)
Definition: active.c:1118