NeoMutt  2021-10-29-220-g2b1eec
Teaching an old dog new tricks
DOXYGEN
newsrc.c File Reference

Read/parse/write an NNTP config file of subscribed newsgroups. More...

#include "config.h"
#include <dirent.h>
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "private.h"
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "conn/lib.h"
#include "mutt.h"
#include "lib.h"
#include "bcache/lib.h"
#include "adata.h"
#include "edata.h"
#include "format_flags.h"
#include "mdata.h"
#include "mutt_account.h"
#include "mutt_logging.h"
#include "mutt_socket.h"
#include "muttlib.h"
#include "protos.h"
#include "hcache/lib.h"
+ Include dependency graph for newsrc.c:

Go to the source code of this file.

Functions

static struct NntpMboxDatamdata_find (struct NntpAccountData *adata, const char *group)
 Find NntpMboxData for given newsgroup or add it. More...
 
void nntp_acache_free (struct NntpMboxData *mdata)
 Remove all temporarily cache files. More...
 
void nntp_newsrc_close (struct NntpAccountData *adata)
 Unlock and close .newsrc file. More...
 
void nntp_group_unread_stat (struct NntpMboxData *mdata)
 Count number of unread articles using .newsrc data. More...
 
int nntp_newsrc_parse (struct NntpAccountData *adata)
 Parse .newsrc file. More...
 
void nntp_newsrc_gen_entries (struct Mailbox *m)
 Generate array of .newsrc entries. More...
 
static int update_file (char *filename, char *buf)
 Update file with new contents. More...
 
int nntp_newsrc_update (struct NntpAccountData *adata)
 Update .newsrc file. More...
 
static void cache_expand (char *dst, size_t dstlen, struct ConnAccount *cac, const char *src)
 Make fully qualified cache file name. More...
 
void nntp_expand_path (char *buf, size_t buflen, struct ConnAccount *cac)
 Make fully qualified url from newsgroup name. More...
 
int nntp_add_group (char *line, void *data)
 Parse newsgroup. More...
 
static int active_get_cache (struct NntpAccountData *adata)
 Load list of all newsgroups from cache. More...
 
int nntp_active_save_cache (struct NntpAccountData *adata)
 Save list of all newsgroups to cache. More...
 
static void nntp_hcache_namer (const char *path, struct Buffer *dest)
 Compose hcache file names - Implements hcache_namer_t -. More...
 
struct HeaderCachenntp_hcache_open (struct NntpMboxData *mdata)
 Open newsgroup hcache. More...
 
void nntp_hcache_update (struct NntpMboxData *mdata, struct HeaderCache *hc)
 Remove stale cached headers. More...
 
static int nntp_bcache_delete (const char *id, struct BodyCache *bcache, void *data)
 Remove bcache file - Implements bcache_list_t -. More...
 
void nntp_bcache_update (struct NntpMboxData *mdata)
 Remove stale cached messages. More...
 
void nntp_delete_group_cache (struct NntpMboxData *mdata)
 Remove hcache and bcache of newsgroup. More...
 
void nntp_clear_cache (struct NntpAccountData *adata)
 Clear the NNTP cache. More...
 
const char * nntp_format_str (char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, intptr_t data, MuttFormatFlags flags)
 Expand the newsrc filename - Implements format_t -. More...
 
static const char * nntp_get_field (enum ConnAccountField field, void *gf_data)
 Get connection login credentials - Implements ConnAccount::get_field() More...
 
struct NntpAccountDatanntp_select_server (struct Mailbox *m, const char *server, bool leave_lock)
 Open a connection to an NNTP server. More...
 
void nntp_article_status (struct Mailbox *m, struct Email *e, char *group, anum_t anum)
 Get status of articles from .newsrc. More...
 
struct NntpMboxDatamutt_newsgroup_subscribe (struct NntpAccountData *adata, char *group)
 Subscribe newsgroup. More...
 
struct NntpMboxDatamutt_newsgroup_unsubscribe (struct NntpAccountData *adata, char *group)
 Unsubscribe newsgroup. More...
 
struct NntpMboxDatamutt_newsgroup_catchup (struct Mailbox *m, struct NntpAccountData *adata, char *group)
 Catchup newsgroup. More...
 
struct NntpMboxDatamutt_newsgroup_uncatchup (struct Mailbox *m, struct NntpAccountData *adata, char *group)
 Uncatchup newsgroup. More...
 
void nntp_mailbox (struct Mailbox *m, char *buf, size_t buflen)
 Get first newsgroup with new messages. More...
 

Detailed Description

Read/parse/write an NNTP config file of subscribed newsgroups.

Authors
  • Brandon Long
  • Andrej Gritsenko
  • Vsevolod Volkov

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file newsrc.c.

Function Documentation

◆ mdata_find()

static struct NntpMboxData* mdata_find ( struct NntpAccountData adata,
const char *  group 
)
static

Find NntpMboxData for given newsgroup or add it.

Parameters
adataNNTP server
groupNewsgroup
Return values
ptrNNTP data
NULLError

Definition at line 73 of file newsrc.c.

74 {
76  if (mdata)
77  return mdata;
78 
79  size_t len = strlen(group) + 1;
80  /* create NntpMboxData structure and add it to hash */
81  mdata = mutt_mem_calloc(1, sizeof(struct NntpMboxData) + len);
82  mdata->group = (char *) mdata + sizeof(struct NntpMboxData);
83  mutt_str_copy(mdata->group, group, len);
84  mdata->adata = adata;
85  mdata->deleted = true;
87 
88  /* add NntpMboxData to list */
90  {
91  adata->groups_max *= 2;
93  }
95 
96  return mdata;
97 }
struct HashElem * mutt_hash_insert(struct HashTable *table, const char *strkey, void *data)
Add a new element to the Hash Table (with string keys)
Definition: hash.c:335
void * mutt_hash_find(const struct HashTable *table, const char *strkey)
Find the HashElem data in a Hash Table element using a key.
Definition: hash.c:362
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:560
void * mdata
Driver specific data.
Definition: mailbox.h:136
struct HashTable * groups_hash
Definition: adata.h:62
unsigned int groups_num
Definition: adata.h:59
unsigned int groups_max
Definition: adata.h:60
void ** groups_list
Definition: adata.h:61
NNTP-specific Mailbox data -.
Definition: mdata.h:33
char * group
Name of newsgroup.
Definition: mdata.h:34
struct NntpAccountData * adata
Definition: mdata.h:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_acache_free()

void nntp_acache_free ( struct NntpMboxData mdata)

Remove all temporarily cache files.

Parameters
mdataNNTP Mailbox data

Definition at line 103 of file newsrc.c.

104 {
105  for (int i = 0; i < NNTP_ACACHE_LEN; i++)
106  {
107  if (mdata->acache[i].path)
108  {
109  unlink(mdata->acache[i].path);
110  FREE(&mdata->acache[i].path);
111  }
112  }
113 }
#define FREE(x)
Definition: memory.h:40
#define NNTP_ACACHE_LEN
Definition: lib.h:82
char * path
Cache path.
Definition: lib.h:69
struct NntpAcache acache[NNTP_ACACHE_LEN]
Definition: mdata.h:48
+ Here is the caller graph for this function:

◆ nntp_newsrc_close()

void nntp_newsrc_close ( struct NntpAccountData adata)

Unlock and close .newsrc file.

Parameters
adataNNTP server

Definition at line 119 of file newsrc.c.

120 {
121  if (!adata->fp_newsrc)
122  return;
123 
124  mutt_debug(LL_DEBUG1, "Unlocking %s\n", adata->newsrc_file);
125  mutt_file_unlock(fileno(adata->fp_newsrc));
126  mutt_file_fclose(&adata->fp_newsrc);
127 }
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
int mutt_file_unlock(int fd)
Unlock a file previously locked by mutt_file_lock()
Definition: file.c:1254
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
FILE * fp_newsrc
Definition: adata.h:51
char * newsrc_file
Definition: adata.h:52
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_group_unread_stat()

void nntp_group_unread_stat ( struct NntpMboxData mdata)

Count number of unread articles using .newsrc data.

Parameters
mdataNNTP Mailbox data

Definition at line 133 of file newsrc.c.

134 {
135  mdata->unread = 0;
136  if ((mdata->last_message == 0) ||
137  (mdata->first_message > mdata->last_message) || !mdata->newsrc_ent)
138  {
139  return;
140  }
141 
142  mdata->unread = mdata->last_message - mdata->first_message + 1;
143  for (unsigned int i = 0; i < mdata->newsrc_len; i++)
144  {
145  anum_t first = mdata->newsrc_ent[i].first;
146  if (first < mdata->first_message)
147  first = mdata->first_message;
148  anum_t last = mdata->newsrc_ent[i].last;
149  if (last > mdata->last_message)
150  last = mdata->last_message;
151  if (first <= last)
152  mdata->unread -= last - first + 1;
153  }
154 }
#define anum_t
Definition: lib.h:60
anum_t last
Last article number in run.
Definition: lib.h:78
anum_t first
First article number in run.
Definition: lib.h:77
anum_t last_message
Definition: mdata.h:37
struct NewsrcEntry * newsrc_ent
Definition: mdata.h:46
anum_t unread
Definition: mdata.h:40
unsigned int newsrc_len
Definition: mdata.h:45
anum_t first_message
Definition: mdata.h:36
+ Here is the caller graph for this function:

◆ nntp_newsrc_parse()

int nntp_newsrc_parse ( struct NntpAccountData adata)

Parse .newsrc file.

Parameters
adataNNTP server
Return values
0Not changed
1Parsed
-1Error

Definition at line 163 of file newsrc.c.

164 {
165  char *line = NULL;
166  struct stat st = { 0 };
167 
168  if (adata->fp_newsrc)
169  {
170  /* if we already have a handle, close it and reopen */
171  mutt_file_fclose(&adata->fp_newsrc);
172  }
173  else
174  {
175  /* if file doesn't exist, create it */
176  adata->fp_newsrc = mutt_file_fopen(adata->newsrc_file, "a");
177  mutt_file_fclose(&adata->fp_newsrc);
178  }
179 
180  /* open .newsrc */
181  adata->fp_newsrc = mutt_file_fopen(adata->newsrc_file, "r");
182  if (!adata->fp_newsrc)
183  {
184  mutt_perror(adata->newsrc_file);
185  return -1;
186  }
187 
188  /* lock it */
189  mutt_debug(LL_DEBUG1, "Locking %s\n", adata->newsrc_file);
190  if (mutt_file_lock(fileno(adata->fp_newsrc), false, true))
191  {
192  mutt_file_fclose(&adata->fp_newsrc);
193  return -1;
194  }
195 
196  if (stat(adata->newsrc_file, &st) != 0)
197  {
198  mutt_perror(adata->newsrc_file);
199  nntp_newsrc_close(adata);
200  return -1;
201  }
202 
203  if ((adata->size == st.st_size) && (adata->mtime == st.st_mtime))
204  return 0;
205 
206  adata->size = st.st_size;
207  adata->mtime = st.st_mtime;
208  adata->newsrc_modified = true;
209  mutt_debug(LL_DEBUG1, "Parsing %s\n", adata->newsrc_file);
210 
211  /* .newsrc has been externally modified or hasn't been loaded yet */
212  for (unsigned int i = 0; i < adata->groups_num; i++)
213  {
214  struct NntpMboxData *mdata = adata->groups_list[i];
215  if (!mdata)
216  continue;
217 
218  mdata->subscribed = false;
219  mdata->newsrc_len = 0;
220  FREE(&mdata->newsrc_ent);
221  }
222 
223  line = mutt_mem_malloc(st.st_size + 1);
224  while (st.st_size && fgets(line, st.st_size + 1, adata->fp_newsrc))
225  {
226  char *b = NULL, *h = NULL;
227  unsigned int j = 1;
228  bool subs = false;
229 
230  /* find end of newsgroup name */
231  char *p = strpbrk(line, ":!");
232  if (!p)
233  continue;
234 
235  /* ":" - subscribed, "!" - unsubscribed */
236  if (*p == ':')
237  subs = true;
238  *p++ = '\0';
239 
240  /* get newsgroup data */
241  struct NntpMboxData *mdata = mdata_find(adata, line);
242  FREE(&mdata->newsrc_ent);
243 
244  /* count number of entries */
245  b = p;
246  while (*b)
247  if (*b++ == ',')
248  j++;
249  mdata->newsrc_ent = mutt_mem_calloc(j, sizeof(struct NewsrcEntry));
250  mdata->subscribed = subs;
251 
252  /* parse entries */
253  j = 0;
254  while (p)
255  {
256  b = p;
257 
258  /* find end of entry */
259  p = strchr(p, ',');
260  if (p)
261  *p++ = '\0';
262 
263  /* first-last or single number */
264  h = strchr(b, '-');
265  if (h)
266  *h++ = '\0';
267  else
268  h = b;
269 
270  if ((sscanf(b, ANUM, &mdata->newsrc_ent[j].first) == 1) &&
271  (sscanf(h, ANUM, &mdata->newsrc_ent[j].last) == 1))
272  {
273  j++;
274  }
275  }
276  if (j == 0)
277  {
278  mdata->newsrc_ent[j].first = 1;
279  mdata->newsrc_ent[j].last = 0;
280  j++;
281  }
282  if (mdata->last_message == 0)
283  mdata->last_message = mdata->newsrc_ent[j - 1].last;
284  mdata->newsrc_len = j;
285  mutt_mem_realloc(&mdata->newsrc_ent, j * sizeof(struct NewsrcEntry));
287  mutt_debug(LL_DEBUG2, "%s\n", mdata->group);
288  }
289  FREE(&line);
290  return 1;
291 }
int mutt_file_lock(int fd, bool excl, bool timeout)
(Try to) Lock a file using fcntl()
Definition: file.c:1206
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:593
#define mutt_perror(...)
Definition: logging.h:88
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
void nntp_newsrc_close(struct NntpAccountData *adata)
Unlock and close .newsrc file.
Definition: newsrc.c:119
void nntp_group_unread_stat(struct NntpMboxData *mdata)
Count number of unread articles using .newsrc data.
Definition: newsrc.c:133
static struct NntpMboxData * mdata_find(struct NntpAccountData *adata, const char *group)
Find NntpMboxData for given newsgroup or add it.
Definition: newsrc.c:73
#define ANUM
Definition: lib.h:61
An entry in a .newsrc (subscribed newsgroups)
Definition: lib.h:76
bool newsrc_modified
Definition: adata.h:50
off_t size
Definition: adata.h:55
time_t mtime
Definition: adata.h:56
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_newsrc_gen_entries()

void nntp_newsrc_gen_entries ( struct Mailbox m)

Generate array of .newsrc entries.

Parameters
mMailbox

Definition at line 297 of file newsrc.c.

298 {
299  if (!m)
300  return;
301 
302  struct NntpMboxData *mdata = m->mdata;
303  anum_t last = 0, first = 1;
304  bool series;
305  unsigned int entries;
306 
307  const short c_sort = cs_subset_sort(NeoMutt->sub, "sort");
308  if (c_sort != SORT_ORDER)
309  {
312  }
313 
314  entries = mdata->newsrc_len;
315  if (!entries)
316  {
317  entries = 5;
318  mdata->newsrc_ent = mutt_mem_calloc(entries, sizeof(struct NewsrcEntry));
319  }
320 
321  /* Set up to fake initial sequence from 1 to the article before the
322  * first article in our list */
323  mdata->newsrc_len = 0;
324  series = true;
325  for (int i = 0; i < m->msg_count; i++)
326  {
327  struct Email *e = m->emails[i];
328  if (!e)
329  break;
330 
331  /* search for first unread */
332  if (series)
333  {
334  /* We don't actually check sequential order, since we mark
335  * "missing" entries as read/deleted */
336  last = nntp_edata_get(e)->article_num;
337  if ((last >= mdata->first_message) && !e->deleted && !e->read)
338  {
339  if (mdata->newsrc_len >= entries)
340  {
341  entries *= 2;
342  mutt_mem_realloc(&mdata->newsrc_ent, entries * sizeof(struct NewsrcEntry));
343  }
344  mdata->newsrc_ent[mdata->newsrc_len].first = first;
345  mdata->newsrc_ent[mdata->newsrc_len].last = last - 1;
346  mdata->newsrc_len++;
347  series = false;
348  }
349  }
350 
351  /* search for first read */
352  else
353  {
354  if (e->deleted || e->read)
355  {
356  first = last + 1;
357  series = true;
358  }
359  last = nntp_edata_get(e)->article_num;
360  }
361  }
362 
363  if (series && (first <= mdata->last_loaded))
364  {
365  if (mdata->newsrc_len >= entries)
366  {
367  entries++;
368  mutt_mem_realloc(&mdata->newsrc_ent, entries * sizeof(struct NewsrcEntry));
369  }
370  mdata->newsrc_ent[mdata->newsrc_len].first = first;
371  mdata->newsrc_ent[mdata->newsrc_len].last = mdata->last_loaded;
372  mdata->newsrc_len++;
373  }
374  mutt_mem_realloc(&mdata->newsrc_ent, mdata->newsrc_len * sizeof(struct NewsrcEntry));
375 
376  if (c_sort != SORT_ORDER)
377  {
378  cs_subset_str_native_set(NeoMutt->sub, "sort", c_sort, NULL);
380  }
381 }
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:211
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition: mailbox.h:181
struct NntpEmailData * nntp_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:58
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:48
The envelope/body of an email.
Definition: email.h:37
bool read
Email is read.
Definition: email.h:48
bool deleted
Email is deleted.
Definition: email.h:76
int msg_count
Total number of messages.
Definition: mailbox.h:91
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
anum_t article_num
NNTP article number.
Definition: edata.h:36
anum_t last_loaded
Definition: mdata.h:38
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:305
+ Here is the call graph for this function:

◆ update_file()

static int update_file ( char *  filename,
char *  buf 
)
static

Update file with new contents.

Parameters
filenameFile to update
bufNew context
Return values
0Success
-1Failure

Definition at line 390 of file newsrc.c.

391 {
392  FILE *fp = NULL;
393  char tmpfile[PATH_MAX];
394  int rc = -1;
395 
396  while (true)
397  {
398  snprintf(tmpfile, sizeof(tmpfile), "%s.tmp", filename);
399  fp = mutt_file_fopen(tmpfile, "w");
400  if (!fp)
401  {
402  mutt_perror(tmpfile);
403  *tmpfile = '\0';
404  break;
405  }
406  if (fputs(buf, fp) == EOF)
407  {
408  mutt_perror(tmpfile);
409  break;
410  }
411  if (mutt_file_fclose(&fp) == EOF)
412  {
413  mutt_perror(tmpfile);
414  fp = NULL;
415  break;
416  }
417  fp = NULL;
418  if (rename(tmpfile, filename) < 0)
419  {
420  mutt_perror(filename);
421  break;
422  }
423  *tmpfile = '\0';
424  rc = 0;
425  break;
426  }
427  mutt_file_fclose(&fp);
428 
429  if (*tmpfile)
430  unlink(tmpfile);
431  return rc;
432 }
#define PATH_MAX
Definition: mutt.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_newsrc_update()

int nntp_newsrc_update ( struct NntpAccountData adata)

Update .newsrc file.

Parameters
adataNNTP server
Return values
0Success
-1Failure

Definition at line 440 of file newsrc.c.

441 {
442  if (!adata)
443  return -1;
444 
445  int rc = -1;
446 
447  size_t buflen = 10240;
448  char *buf = mutt_mem_calloc(1, buflen);
449  size_t off = 0;
450 
451  /* we will generate full newsrc here */
452  for (unsigned int i = 0; i < adata->groups_num; i++)
453  {
454  struct NntpMboxData *mdata = adata->groups_list[i];
455 
456  if (!mdata || !mdata->newsrc_ent)
457  continue;
458 
459  /* write newsgroup name */
460  if (off + strlen(mdata->group) + 3 > buflen)
461  {
462  buflen *= 2;
463  mutt_mem_realloc(&buf, buflen);
464  }
465  snprintf(buf + off, buflen - off, "%s%c ", mdata->group, mdata->subscribed ? ':' : '!');
466  off += strlen(buf + off);
467 
468  /* write entries */
469  for (unsigned int j = 0; j < mdata->newsrc_len; j++)
470  {
471  if (off + 1024 > buflen)
472  {
473  buflen *= 2;
474  mutt_mem_realloc(&buf, buflen);
475  }
476  if (j)
477  buf[off++] = ',';
478  if (mdata->newsrc_ent[j].first == mdata->newsrc_ent[j].last)
479  snprintf(buf + off, buflen - off, "%u", mdata->newsrc_ent[j].first);
480  else if (mdata->newsrc_ent[j].first < mdata->newsrc_ent[j].last)
481  {
482  snprintf(buf + off, buflen - off, "%u-%u", mdata->newsrc_ent[j].first,
483  mdata->newsrc_ent[j].last);
484  }
485  off += strlen(buf + off);
486  }
487  buf[off++] = '\n';
488  }
489  buf[off] = '\0';
490 
491  /* newrc being fully rewritten */
492  mutt_debug(LL_DEBUG1, "Updating %s\n", adata->newsrc_file);
493  if (adata->newsrc_file && (update_file(adata->newsrc_file, buf) == 0))
494  {
495  struct stat st = { 0 };
496 
497  rc = stat(adata->newsrc_file, &st);
498  if (rc == 0)
499  {
500  adata->size = st.st_size;
501  adata->mtime = st.st_mtime;
502  }
503  else
504  {
505  mutt_perror(adata->newsrc_file);
506  }
507  }
508  FREE(&buf);
509  return rc;
510 }
static int update_file(char *filename, char *buf)
Update file with new contents.
Definition: newsrc.c:390
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cache_expand()

static void cache_expand ( char *  dst,
size_t  dstlen,
struct ConnAccount cac,
const char *  src 
)
static

Make fully qualified cache file name.

Parameters
dstBuffer for filename
dstlenLength of buffer
cacAccount
srcPath to add to the URL

Definition at line 519 of file newsrc.c.

520 {
521  char *c = NULL;
522  char file[PATH_MAX];
523 
524  /* server subdirectory */
525  if (cac)
526  {
527  struct Url url = { 0 };
528 
529  mutt_account_tourl(cac, &url);
530  url.path = mutt_str_dup(src);
531  url_tostring(&url, file, sizeof(file), U_PATH);
532  FREE(&url.path);
533  }
534  else
535  mutt_str_copy(file, src ? src : "", sizeof(file));
536 
537  const char *const c_news_cache_dir =
538  cs_subset_path(NeoMutt->sub, "news_cache_dir");
539  snprintf(dst, dstlen, "%s/%s", c_news_cache_dir, file);
540 
541  /* remove trailing slash */
542  c = dst + strlen(dst) - 1;
543  if (*c == '/')
544  *c = '\0';
545 
546  struct Buffer *tmp = mutt_buffer_pool_get();
547  mutt_buffer_addstr(tmp, dst);
549  mutt_encode_path(tmp, dst);
550  mutt_str_copy(dst, mutt_buffer_string(tmp), dstlen);
552 }
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:181
void mutt_account_tourl(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
Definition: mutt_account.c:79
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:322
void mutt_encode_path(struct Buffer *buf, const char *src)
Convert a path to 'us-ascii'.
Definition: muttlib.c:1490
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
String manipulation buffer.
Definition: buffer.h:34
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:69
char * src
Raw URL string.
Definition: url.h:77
char * path
Path.
Definition: url.h:75
int url_tostring(struct Url *url, char *dest, size_t len, uint8_t flags)
Output the URL string for a given Url object.
Definition: url.c:418
#define U_PATH
Definition: url.h:50
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_expand_path()

void nntp_expand_path ( char *  buf,
size_t  buflen,
struct ConnAccount cac 
)

Make fully qualified url from newsgroup name.

Parameters
bufBuffer for the result
buflenLength of buffer
cacAccount to serialise

Definition at line 560 of file newsrc.c.

561 {
562  struct Url url = { 0 };
563 
564  mutt_account_tourl(cac, &url);
565  url.path = mutt_str_dup(buf);
566  url_tostring(&url, buf, buflen, U_NO_FLAGS);
567  FREE(&url.path);
568 }
#define U_NO_FLAGS
Definition: url.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_add_group()

int nntp_add_group ( char *  line,
void *  data 
)

Parse newsgroup.

Parameters
lineString to parse
dataNNTP data
Return values
0Always

Definition at line 576 of file newsrc.c.

577 {
578  struct NntpAccountData *adata = data;
579  struct NntpMboxData *mdata = NULL;
580  char group[1024] = { 0 };
581  char desc[8192] = { 0 };
582  char mod;
583  anum_t first, last;
584 
585  if (!adata || !line)
586  return 0;
587 
588  /* These sscanf limits must match the sizes of the group and desc arrays */
589  if (sscanf(line, "%1023s " ANUM " " ANUM " %c %8191[^\n]", group, &last,
590  &first, &mod, desc) < 4)
591  {
592  mutt_debug(LL_DEBUG2, "Can't parse server line: %s\n", line);
593  return 0;
594  }
595 
597  mdata->deleted = false;
598  mdata->first_message = first;
599  mdata->last_message = last;
600  mdata->allowed = (mod == 'y') || (mod == 'm');
601  mutt_str_replace(&mdata->desc, desc);
602  if (mdata->newsrc_ent || (mdata->last_cached != 0))
604  else if (mdata->last_message && (mdata->first_message <= mdata->last_message))
605  mdata->unread = mdata->last_message - mdata->first_message + 1;
606  else
607  mdata->unread = 0;
608  return 0;
609 }
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:257
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
NNTP-specific Account data -.
Definition: adata.h:37
char * desc
Description of newsgroup.
Definition: mdata.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ active_get_cache()

static int active_get_cache ( struct NntpAccountData adata)
static

Load list of all newsgroups from cache.

Parameters
adataNNTP server
Return values
0Success
-1Failure

Definition at line 617 of file newsrc.c.

618 {
619  char buf[8192];
620  char file[4096];
621  time_t t;
622 
623  cache_expand(file, sizeof(file), &adata->conn->account, ".active");
624  mutt_debug(LL_DEBUG1, "Parsing %s\n", file);
625  FILE *fp = mutt_file_fopen(file, "r");
626  if (!fp)
627  return -1;
628 
629  if (!fgets(buf, sizeof(buf), fp) || (sscanf(buf, "%jd%4095s", &t, file) != 1) || (t == 0))
630  {
631  mutt_file_fclose(&fp);
632  return -1;
633  }
634  adata->newgroups_time = t;
635 
636  mutt_message(_("Loading list of groups from cache..."));
637  while (fgets(buf, sizeof(buf), fp))
638  nntp_add_group(buf, adata);
639  nntp_add_group(NULL, NULL);
640  mutt_file_fclose(&fp);
642  return 0;
643 }
#define mutt_message(...)
Definition: logging.h:86
#define _(a)
Definition: message.h:28
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
int nntp_add_group(char *line, void *data)
Parse newsgroup.
Definition: newsrc.c:576
static void cache_expand(char *dst, size_t dstlen, struct ConnAccount *cac, const char *src)
Make fully qualified cache file name.
Definition: newsrc.c:519
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:50
time_t newgroups_time
Definition: adata.h:57
struct Connection * conn
Connection to NNTP Server.
Definition: adata.h:63
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_active_save_cache()

int nntp_active_save_cache ( struct NntpAccountData adata)

Save list of all newsgroups to cache.

Parameters
adataNNTP server
Return values
0Success
-1Failure

Definition at line 651 of file newsrc.c.

652 {
653  if (!adata->cacheable)
654  return 0;
655 
656  size_t buflen = 10240;
657  char *buf = mutt_mem_calloc(1, buflen);
658  snprintf(buf, buflen, "%lu\n", (unsigned long) adata->newgroups_time);
659  size_t off = strlen(buf);
660 
661  for (unsigned int i = 0; i < adata->groups_num; i++)
662  {
663  struct NntpMboxData *mdata = adata->groups_list[i];
664 
665  if (!mdata || mdata->deleted)
666  continue;
667 
668  if ((off + strlen(mdata->group) + (mdata->desc ? strlen(mdata->desc) : 0) + 50) > buflen)
669  {
670  buflen *= 2;
671  mutt_mem_realloc(&buf, buflen);
672  }
673  snprintf(buf + off, buflen - off, "%s %u %u %c%s%s\n", mdata->group,
674  mdata->last_message, mdata->first_message, mdata->allowed ? 'y' : 'n',
675  mdata->desc ? " " : "", mdata->desc ? mdata->desc : "");
676  off += strlen(buf + off);
677  }
678 
679  char file[PATH_MAX];
680  cache_expand(file, sizeof(file), &adata->conn->account, ".active");
681  mutt_debug(LL_DEBUG1, "Updating %s\n", file);
682  int rc = update_file(file, buf);
683  FREE(&buf);
684  return rc;
685 }
bool cacheable
Definition: adata.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_hcache_open()

struct HeaderCache* nntp_hcache_open ( struct NntpMboxData mdata)

Open newsgroup hcache.

Parameters
mdataNNTP Mailbox data
Return values
ptrHeader cache
NULLError

Definition at line 710 of file newsrc.c.

711 {
712  struct Url url = { 0 };
713  char file[PATH_MAX];
714 
715  const bool c_save_unsubscribed =
716  cs_subset_bool(NeoMutt->sub, "save_unsubscribed");
717  if (!mdata->adata || !mdata->adata->cacheable || !mdata->adata->conn || !mdata->group ||
718  !(mdata->newsrc_ent || mdata->subscribed || c_save_unsubscribed))
719  {
720  return NULL;
721  }
722 
723  mutt_account_tourl(&mdata->adata->conn->account, &url);
724  url.path = mdata->group;
725  url_tostring(&url, file, sizeof(file), U_PATH);
726  const char *const c_news_cache_dir =
727  cs_subset_path(NeoMutt->sub, "news_cache_dir");
728  return mutt_hcache_open(c_news_cache_dir, file, nntp_hcache_namer);
729 }
static void nntp_hcache_namer(const char *path, struct Buffer *dest)
Compose hcache file names - Implements hcache_namer_t -.
Definition: newsrc.c:691
struct HeaderCache * mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:335
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
bool subscribed
Definition: mdata.h:41
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_hcache_update()

void nntp_hcache_update ( struct NntpMboxData mdata,
struct HeaderCache hc 
)

Remove stale cached headers.

Parameters
mdataNNTP Mailbox data
hcHeader cache

Definition at line 736 of file newsrc.c.

737 {
738  if (!hc)
739  return;
740 
741  char buf[32];
742  bool old = false;
743  anum_t first = 0, last = 0;
744 
745  /* fetch previous values of first and last */
746  size_t dlen = 0;
747  void *hdata = mutt_hcache_fetch_raw(hc, "index", 5, &dlen);
748  if (hdata)
749  {
750  mutt_debug(LL_DEBUG2, "mutt_hcache_fetch index: %s\n", (char *) hdata);
751  if (sscanf(hdata, ANUM " " ANUM, &first, &last) == 2)
752  {
753  old = true;
754  mdata->last_cached = last;
755 
756  /* clean removed headers from cache */
757  for (anum_t current = first; current <= last; current++)
758  {
759  if ((current >= mdata->first_message) && (current <= mdata->last_message))
760  continue;
761 
762  snprintf(buf, sizeof(buf), "%u", current);
763  mutt_debug(LL_DEBUG2, "mutt_hcache_delete_record %s\n", buf);
764  mutt_hcache_delete_record(hc, buf, strlen(buf));
765  }
766  }
767  mutt_hcache_free_raw(hc, &hdata);
768  }
769 
770  /* store current values of first and last */
771  if (!old || (mdata->first_message != first) || (mdata->last_message != last))
772  {
773  snprintf(buf, sizeof(buf), "%u %u", mdata->first_message, mdata->last_message);
774  mutt_debug(LL_DEBUG2, "mutt_hcache_store index: %s\n", buf);
775  mutt_hcache_store_raw(hc, "index", 5, buf, strlen(buf) + 1);
776  }
777 }
int mutt_hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:640
int mutt_hcache_store_raw(struct HeaderCache *hc, const char *key, size_t keylen, void *data, size_t dlen)
Store a key / data pair.
Definition: hcache.c:618
void mutt_hcache_free_raw(struct HeaderCache *hc, void **data)
Multiplexor for StoreOps::free.
Definition: hcache.c:544
void * mutt_hcache_fetch_raw(struct HeaderCache *hc, const char *key, size_t keylen, size_t *dlen)
Fetch a message's header from the cache.
Definition: hcache.c:524
anum_t last_cached
Definition: mdata.h:39
+ Here is the call graph for this function:

◆ nntp_bcache_update()

void nntp_bcache_update ( struct NntpMboxData mdata)

Remove stale cached messages.

Parameters
mdataNNTP Mailbox data

Definition at line 804 of file newsrc.c.

805 {
807 }
int mutt_bcache_list(struct BodyCache *bcache, bcache_list_t want_id, void *data)
Find matching entries in the Body Cache.
Definition: bcache.c:331
static int nntp_bcache_delete(const char *id, struct BodyCache *bcache, void *data)
Remove bcache file - Implements bcache_list_t -.
Definition: newsrc.c:784
struct BodyCache * bcache
Definition: mdata.h:49
+ Here is the call graph for this function:

◆ nntp_delete_group_cache()

void nntp_delete_group_cache ( struct NntpMboxData mdata)

Remove hcache and bcache of newsgroup.

Parameters
mdataNNTP Mailbox data

Definition at line 813 of file newsrc.c.

814 {
815  if (!mdata || !mdata->adata || !mdata->adata->cacheable)
816  return;
817 
818 #ifdef USE_HCACHE
819  struct Buffer file = mutt_buffer_make(PATH_MAX);
820  nntp_hcache_namer(mdata->group, &file);
821  cache_expand(file.data, file.dsize, &mdata->adata->conn->account,
822  mutt_buffer_string(&file));
823  unlink(mutt_buffer_string(&file));
824  mdata->last_cached = 0;
825  mutt_debug(LL_DEBUG2, "%s\n", mutt_buffer_string(&file));
826  mutt_buffer_dealloc(&file);
827 #endif
828 
829  if (!mdata->bcache)
830  {
831  mdata->bcache = mutt_bcache_open(&mdata->adata->conn->account, mdata->group);
832  }
833  if (mdata->bcache)
834  {
835  mutt_debug(LL_DEBUG2, "%s/*\n", mdata->group);
837  mutt_bcache_close(&mdata->bcache);
838  }
839 }
struct BodyCache * mutt_bcache_open(struct ConnAccount *account, const char *mailbox)
Open an Email-Body Cache.
Definition: bcache.c:145
void mutt_bcache_close(struct BodyCache **bcache)
Close an Email-Body Cache.
Definition: bcache.c:166
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_clear_cache()

void nntp_clear_cache ( struct NntpAccountData adata)

Clear the NNTP cache.

Parameters
adataNNTP server

Remove hcache and bcache of all unexistent and unsubscribed newsgroups

Definition at line 847 of file newsrc.c.

848 {
849  char file[PATH_MAX];
850  char *fp = NULL;
851  struct dirent *entry = NULL;
852  DIR *dp = NULL;
853 
854  if (!adata || !adata->cacheable)
855  return;
856 
857  cache_expand(file, sizeof(file), &adata->conn->account, NULL);
858  dp = opendir(file);
859  if (dp)
860  {
861  mutt_strn_cat(file, sizeof(file), "/", 1);
862  fp = file + strlen(file);
863  while ((entry = readdir(dp)))
864  {
865  char *group = entry->d_name;
866  struct stat st = { 0 };
867  struct NntpMboxData *mdata = NULL;
868  struct NntpMboxData tmp_mdata;
869 
870  if (mutt_str_equal(group, ".") || mutt_str_equal(group, ".."))
871  continue;
872  *fp = '\0';
873  mutt_strn_cat(file, sizeof(file), group, strlen(group));
874  if (stat(file, &st) != 0)
875  continue;
876 
877 #ifdef USE_HCACHE
878  if (S_ISREG(st.st_mode))
879  {
880  char *ext = group + strlen(group) - 7;
881  if ((strlen(group) < 8) || !mutt_str_equal(ext, ".hcache"))
882  continue;
883  *ext = '\0';
884  }
885  else
886 #endif
887  if (!S_ISDIR(st.st_mode))
888  continue;
889 
890  const bool c_save_unsubscribed =
891  cs_subset_bool(NeoMutt->sub, "save_unsubscribed");
893  if (!mdata)
894  {
895  mdata = &tmp_mdata;
896  mdata->adata = adata;
897  mdata->group = group;
898  mdata->bcache = NULL;
899  }
900  else if (mdata->newsrc_ent || mdata->subscribed || c_save_unsubscribed)
901  continue;
902 
904  if (S_ISDIR(st.st_mode))
905  {
906  rmdir(file);
907  mutt_debug(LL_DEBUG2, "%s\n", file);
908  }
909  }
910  closedir(dp);
911  }
912 }
char * mutt_strn_cat(char *d, size_t l, const char *s, size_t sl)
Concatenate two strings.
Definition: string.c:225
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:715
void nntp_delete_group_cache(struct NntpMboxData *mdata)
Remove hcache and bcache of newsgroup.
Definition: newsrc.c:813
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_get_field()

static const char* nntp_get_field ( enum ConnAccountField  field,
void *  gf_data 
)
static

Get connection login credentials - Implements ConnAccount::get_field()

Definition at line 989 of file newsrc.c.

990 {
991  switch (field)
992  {
993  case MUTT_CA_LOGIN:
994  case MUTT_CA_USER:
995  return cs_subset_string(NeoMutt->sub, "nntp_user");
996  case MUTT_CA_PASS:
997  return cs_subset_string(NeoMutt->sub, "nntp_pass");
998  case MUTT_CA_OAUTH_CMD:
999  case MUTT_CA_HOST:
1000  default:
1001  return NULL;
1002  }
1003 }
@ MUTT_CA_OAUTH_CMD
OAuth refresh command.
Definition: connaccount.h:38
@ MUTT_CA_USER
User name.
Definition: connaccount.h:36
@ MUTT_CA_LOGIN
Login name.
Definition: connaccount.h:35
@ MUTT_CA_HOST
Server name.
Definition: connaccount.h:34
@ MUTT_CA_PASS
Password.
Definition: connaccount.h:37
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_select_server()

struct NntpAccountData* nntp_select_server ( struct Mailbox m,
const char *  server,
bool  leave_lock 
)

Open a connection to an NNTP server.

Parameters
mMailbox
serverServer URL
leave_lockLeave the server locked?
Return values
ptrNNTP server
NULLError

Automatically loads a newsrc into memory, if necessary. Checks the size/mtime of a newsrc file, if it doesn't match, load again. Hmm, if a system has broken mtimes, this might mean the file is reloaded every time, which we'd have to fix.

Definition at line 1018 of file newsrc.c.

1019 {
1020  char file[PATH_MAX];
1021  int rc;
1022  struct ConnAccount cac = { { 0 } };
1023  struct NntpAccountData *adata = NULL;
1024  struct Connection *conn = NULL;
1025 
1026  if (!server || (*server == '\0'))
1027  {
1028  mutt_error(_("No news server defined"));
1029  return NULL;
1030  }
1031 
1032  /* create account from news server url */
1033  cac.flags = 0;
1034  cac.port = NNTP_PORT;
1035  cac.type = MUTT_ACCT_TYPE_NNTP;
1036  cac.service = "nntp";
1037  cac.get_field = nntp_get_field;
1038 
1039  snprintf(file, sizeof(file), "%s%s", strstr(server, "://") ? "" : "news://", server);
1040  struct Url *url = url_parse(file);
1041  if (!url || (url->path && *url->path) ||
1042  !((url->scheme == U_NNTP) || (url->scheme == U_NNTPS)) || !url->host ||
1043  (mutt_account_fromurl(&cac, url) < 0))
1044  {
1045  url_free(&url);
1046  mutt_error(_("%s is an invalid news server specification"), server);
1047  return NULL;
1048  }
1049  if (url->scheme == U_NNTPS)
1050  {
1051  cac.flags |= MUTT_ACCT_SSL;
1052  cac.port = NNTP_SSL_PORT;
1053  }
1054  url_free(&url);
1055 
1056  /* find connection by account */
1057  conn = mutt_conn_find(&cac);
1058  if (!conn)
1059  return NULL;
1060  if (!(conn->account.flags & MUTT_ACCT_USER) && cac.flags & MUTT_ACCT_USER)
1061  {
1062  conn->account.flags |= MUTT_ACCT_USER;
1063  conn->account.user[0] = '\0';
1064  }
1065 
1066  /* news server already exists */
1067  // adata = conn->data;
1068  if (adata)
1069  {
1070  if (adata->status == NNTP_BYE)
1071  adata->status = NNTP_NONE;
1072  if (nntp_open_connection(adata) < 0)
1073  return NULL;
1074 
1075  rc = nntp_newsrc_parse(adata);
1076  if (rc < 0)
1077  return NULL;
1078 
1079  /* check for new newsgroups */
1080  if (!leave_lock && (nntp_check_new_groups(m, adata) < 0))
1081  rc = -1;
1082 
1083  /* .newsrc has been externally modified */
1084  if (rc > 0)
1085  nntp_clear_cache(adata);
1086  if ((rc < 0) || !leave_lock)
1087  nntp_newsrc_close(adata);
1088  return (rc < 0) ? NULL : adata;
1089  }
1090 
1091  /* new news server */
1092  adata = nntp_adata_new(conn);
1093 
1094  rc = nntp_open_connection(adata);
1095 
1096  /* try to create cache directory and enable caching */
1097  adata->cacheable = false;
1098  const char *const c_news_cache_dir =
1099  cs_subset_path(NeoMutt->sub, "news_cache_dir");
1100  if ((rc >= 0) && c_news_cache_dir)
1101  {
1102  cache_expand(file, sizeof(file), &conn->account, NULL);
1103  if (mutt_file_mkdir(file, S_IRWXU) < 0)
1104  {
1105  mutt_error(_("Can't create %s: %s"), file, strerror(errno));
1106  }
1107  adata->cacheable = true;
1108  }
1109 
1110  /* load .newsrc */
1111  if (rc >= 0)
1112  {
1113  const char *const c_newsrc = cs_subset_path(NeoMutt->sub, "newsrc");
1114  mutt_expando_format(file, sizeof(file), 0, sizeof(file), NONULL(c_newsrc),
1115  nntp_format_str, (intptr_t) adata, MUTT_FORMAT_NO_FLAGS);
1116  mutt_expand_path(file, sizeof(file));
1117  adata->newsrc_file = mutt_str_dup(file);
1118  rc = nntp_newsrc_parse(adata);
1119  }
1120  if (rc >= 0)
1121  {
1122  /* try to load list of newsgroups from cache */
1123  if (adata->cacheable && (active_get_cache(adata) == 0))
1124  rc = nntp_check_new_groups(m, adata);
1125 
1126  /* load list of newsgroups from server */
1127  else
1128  rc = nntp_active_fetch(adata, false);
1129  }
1130 
1131  if (rc >= 0)
1132  nntp_clear_cache(adata);
1133 
1134 #ifdef USE_HCACHE
1135  /* check cache files */
1136  if ((rc >= 0) && adata->cacheable)
1137  {
1138  struct dirent *entry = NULL;
1139  DIR *dp = opendir(file);
1140 
1141  if (dp)
1142  {
1143  while ((entry = readdir(dp)))
1144  {
1145  struct HeaderCache *hc = NULL;
1146  void *hdata = NULL;
1147  char *group = entry->d_name;
1148 
1149  char *p = group + strlen(group) - 7;
1150  if ((strlen(group) < 8) || (strcmp(p, ".hcache") != 0))
1151  continue;
1152  *p = '\0';
1154  if (!mdata)
1155  continue;
1156 
1157  hc = nntp_hcache_open(mdata);
1158  if (!hc)
1159  continue;
1160 
1161  /* fetch previous values of first and last */
1162  size_t dlen = 0;
1163  hdata = mutt_hcache_fetch_raw(hc, "index", 5, &dlen);
1164  if (hdata)
1165  {
1166  anum_t first, last;
1167 
1168  if (sscanf(hdata, ANUM " " ANUM, &first, &last) == 2)
1169  {
1170  if (mdata->deleted)
1171  {
1172  mdata->first_message = first;
1173  mdata->last_message = last;
1174  }
1175  if ((last >= mdata->first_message) && (last <= mdata->last_message))
1176  {
1177  mdata->last_cached = last;
1178  mutt_debug(LL_DEBUG2, "%s last_cached=%u\n", mdata->group, last);
1179  }
1180  }
1181  mutt_hcache_free_raw(hc, &hdata);
1182  }
1183  mutt_hcache_close(hc);
1184  }
1185  closedir(dp);
1186  }
1187  }
1188 #endif
1189 
1190  if ((rc < 0) || !leave_lock)
1192 
1193  if (rc < 0)
1194  {
1196  FREE(&adata->groups_list);
1197  FREE(&adata->newsrc_file);
1199  FREE(&adata);
1200  mutt_socket_close(conn);
1201  FREE(&conn);
1202  return NULL;
1203  }
1204 
1205  return adata;
1206 }
#define MUTT_ACCT_SSL
Account uses SSL/TLS.
Definition: connaccount.h:47
#define MUTT_ACCT_USER
User field has been set.
Definition: connaccount.h:44
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:905
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
const char * nntp_format_str(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, intptr_t data, MuttFormatFlags flags)
Expand the newsrc filename - Implements format_t -.
Definition: newsrc.c:926
void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t callback, intptr_t data, MuttFormatFlags flags)
Expand expandos (x) in a string -.
Definition: muttlib.c:780
#define mutt_error(...)
Definition: logging.h:87
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:457
void mutt_hcache_close(struct HeaderCache *hc)
Multiplexor for StoreOps::close.
Definition: hcache.c:438
int mutt_account_fromurl(struct ConnAccount *cac, const struct Url *url)
Fill ConnAccount with information from url.
Definition: mutt_account.c:43
@ MUTT_ACCT_TYPE_NNTP
Nntp (Usenet) Account.
Definition: mutt_account.h:40
struct Connection * mutt_conn_find(const struct ConnAccount *cac)
Find a connection from a list.
Definition: mutt_socket.c:89
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:122
void nntp_clear_cache(struct NntpAccountData *adata)
Clear the NNTP cache.
Definition: newsrc.c:847
static const char * nntp_get_field(enum ConnAccountField field, void *gf_data)
Get connection login credentials - Implements ConnAccount::get_field()
Definition: newsrc.c:989
int nntp_newsrc_parse(struct NntpAccountData *adata)
Parse .newsrc file.
Definition: newsrc.c:163
static int active_get_cache(struct NntpAccountData *adata)
Load list of all newsgroups from cache.
Definition: newsrc.c:617
struct HeaderCache * nntp_hcache_open(struct NntpMboxData *mdata)
Open newsgroup hcache.
Definition: newsrc.c:710
struct NntpAccountData * nntp_adata_new(struct Connection *conn)
Allocate and initialise a new NntpAccountData structure.
Definition: adata.c:62
int nntp_active_fetch(struct NntpAccountData *adata, bool mark_new)
Fetch list of all newsgroups from server.
Definition: nntp.c:1963
#define NNTP_SSL_PORT
Definition: private.h:37
@ NNTP_NONE
No connection to server.
Definition: private.h:44
@ NNTP_BYE
Disconnected from server.
Definition: private.h:46
#define NNTP_PORT
Definition: private.h:36
int nntp_check_new_groups(struct Mailbox *m, struct NntpAccountData *adata)
Check for new groups/articles in subscribed groups.
Definition: nntp.c:2032
int nntp_open_connection(struct NntpAccountData *adata)
Connect to server, authenticate and get capabilities.
Definition: nntp.c:1712
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition: socket.c:97
#define NONULL(x)
Definition: string2.h:37
Login details for a remote server.
Definition: connaccount.h:53
char user[128]
Username.
Definition: connaccount.h:56
const char * service
Name of the service, e.g. "imap".
Definition: connaccount.h:61
const char *(* get_field)(enum ConnAccountField field, void *gf_data)
Function to get some login credentials.
Definition: connaccount.h:68
unsigned char type
Connection type, e.g. MUTT_ACCT_TYPE_IMAP.
Definition: connaccount.h:59
MuttAccountFlags flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition: connaccount.h:60
unsigned short port
Port to connect to.
Definition: connaccount.h:58
Header cache structure.
Definition: lib.h:87
unsigned int status
Definition: adata.h:48
char * authenticators
Definition: adata.h:53
char * host
Host.
Definition: url.h:73
enum UrlScheme scheme
Scheme, e.g. U_SMTPS.
Definition: url.h:70
struct Url * url_parse(const char *src)
Fill in Url.
Definition: url.c:234
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:123
@ U_NNTPS
Url is nntps://.
Definition: url.h:42
@ U_NNTP
Url is nntp://.
Definition: url.h:41
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_article_status()

void nntp_article_status ( struct Mailbox m,
struct Email e,
char *  group,
anum_t  anum 
)

Get status of articles from .newsrc.

Parameters
mMailbox
eEmail
groupNewsgroup
anumArticle number

Full status flags are not supported by nntp, but we can fake some of them: Read = a read message number is in the .newsrc New = not read and not cached Old = not read but cached

Definition at line 1220 of file newsrc.c.

1221 {
1222  struct NntpMboxData *mdata = m->mdata;
1223 
1224  if (group)
1225  mdata = mutt_hash_find(mdata->adata->groups_hash, group);
1226 
1227  if (!mdata)
1228  return;
1229 
1230  for (unsigned int i = 0; i < mdata->newsrc_len; i++)
1231  {
1232  if ((anum >= mdata->newsrc_ent[i].first) && (anum <= mdata->newsrc_ent[i].last))
1233  {
1234  /* can't use mutt_set_flag() because ctx_update() didn't get called yet */
1235  e->read = true;
1236  return;
1237  }
1238  }
1239 
1240  /* article was not cached yet, it's new */
1241  if (anum > mdata->last_cached)
1242  return;
1243 
1244  /* article isn't read but cached, it's old */
1245  const bool c_mark_old = cs_subset_bool(NeoMutt->sub, "mark_old");
1246  if (c_mark_old)
1247  e->old = true;
1248 }
bool old
Email is seen, but unread.
Definition: email.h:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_newsgroup_subscribe()

struct NntpMboxData* mutt_newsgroup_subscribe ( struct NntpAccountData adata,
char *  group 
)

Subscribe newsgroup.

Parameters
adataNNTP server
groupNewsgroup
Return values
ptrNNTP data
NULLError

Definition at line 1257 of file newsrc.c.

1258 {
1259  if (!adata || !adata->groups_hash || !group || (*group == '\0'))
1260  return NULL;
1261 
1262  struct NntpMboxData *mdata = mdata_find(adata, group);
1263  mdata->subscribed = true;
1264  if (!mdata->newsrc_ent)
1265  {
1266  mdata->newsrc_ent = mutt_mem_calloc(1, sizeof(struct NewsrcEntry));
1267  mdata->newsrc_len = 1;
1268  mdata->newsrc_ent[0].first = 1;
1269  mdata->newsrc_ent[0].last = 0;
1270  }
1271  return mdata;
1272 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_newsgroup_unsubscribe()

struct NntpMboxData* mutt_newsgroup_unsubscribe ( struct NntpAccountData adata,
char *  group 
)

Unsubscribe newsgroup.

Parameters
adataNNTP server
groupNewsgroup
Return values
ptrNNTP data
NULLError

Definition at line 1281 of file newsrc.c.

1282 {
1283  if (!adata || !adata->groups_hash || !group || (*group == '\0'))
1284  return NULL;
1285 
1287  if (!mdata)
1288  return NULL;
1289 
1290  mdata->subscribed = false;
1291  const bool c_save_unsubscribed =
1292  cs_subset_bool(NeoMutt->sub, "save_unsubscribed");
1293  if (!c_save_unsubscribed)
1294  {
1295  mdata->newsrc_len = 0;
1296  FREE(&mdata->newsrc_ent);
1297  }
1298  return mdata;
1299 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_newsgroup_catchup()

struct NntpMboxData* mutt_newsgroup_catchup ( struct Mailbox m,
struct NntpAccountData adata,
char *  group 
)

Catchup newsgroup.

Parameters
mMailbox
adataNNTP server
groupNewsgroup
Return values
ptrNNTP data
NULLError

Definition at line 1309 of file newsrc.c.

1311 {
1312  if (!adata || !adata->groups_hash || !group || (*group == '\0'))
1313  return NULL;
1314 
1316  if (!mdata)
1317  return NULL;
1318 
1319  if (mdata->newsrc_ent)
1320  {
1321  mutt_mem_realloc(&mdata->newsrc_ent, sizeof(struct NewsrcEntry));
1322  mdata->newsrc_len = 1;
1323  mdata->newsrc_ent[0].first = 1;
1324  mdata->newsrc_ent[0].last = mdata->last_message;
1325  }
1326  mdata->unread = 0;
1327  if (m && (m->mdata == mdata))
1328  {
1329  for (unsigned int i = 0; i < m->msg_count; i++)
1330  {
1331  struct Email *e = m->emails[i];
1332  if (!e)
1333  break;
1334  mutt_set_flag(m, e, MUTT_READ, true);
1335  }
1336  }
1337  return mdata;
1338 }
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:92
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:66
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_newsgroup_uncatchup()

struct NntpMboxData* mutt_newsgroup_uncatchup ( struct Mailbox m,
struct NntpAccountData adata,
char *  group 
)

Uncatchup newsgroup.

Parameters
mMailbox
adataNNTP server
groupNewsgroup
Return values
ptrNNTP data
NULLError

Definition at line 1348 of file newsrc.c.

1350 {
1351  if (!adata || !adata->groups_hash || !group || (*group == '\0'))
1352  return NULL;
1353 
1355  if (!mdata)
1356  return NULL;
1357 
1358  if (mdata->newsrc_ent)
1359  {
1360  mutt_mem_realloc(&mdata->newsrc_ent, sizeof(struct NewsrcEntry));
1361  mdata->newsrc_len = 1;
1362  mdata->newsrc_ent[0].first = 1;
1363  mdata->newsrc_ent[0].last = mdata->first_message - 1;
1364  }
1365  if (m && (m->mdata == mdata))
1366  {
1367  mdata->unread = m->msg_count;
1368  for (unsigned int i = 0; i < m->msg_count; i++)
1369  {
1370  struct Email *e = m->emails[i];
1371  if (!e)
1372  break;
1373  mutt_set_flag(m, e, MUTT_READ, false);
1374  }
1375  }
1376  else
1377  {
1378  mdata->unread = mdata->last_message;
1379  if (mdata->newsrc_ent)
1380  mdata->unread -= mdata->newsrc_ent[0].last;
1381  }
1382  return mdata;
1383 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_mailbox()

void nntp_mailbox ( struct Mailbox m,
char *  buf,
size_t  buflen 
)

Get first newsgroup with new messages.

Parameters
mMailbox
bufBuffer for result
buflenLength of buffer

Definition at line 1391 of file newsrc.c.

1392 {
1393  if (!m)
1394  return;
1395 
1396  for (unsigned int i = 0; i < CurrentNewsSrv->groups_num; i++)
1397  {
1399 
1400  if (!mdata || !mdata->subscribed || !mdata->unread)
1401  continue;
1402 
1403  if ((m->type == MUTT_NNTP) &&
1404  mutt_str_equal(mdata->group, ((struct NntpMboxData *) m->mdata)->group))
1405  {
1406  unsigned int unread = 0;
1407 
1408  for (unsigned int j = 0; j < m->msg_count; j++)
1409  {
1410  struct Email *e = m->emails[j];
1411  if (!e)
1412  break;
1413  if (!e->read && !e->deleted)
1414  unread++;
1415  }
1416  if (unread == 0)
1417  continue;
1418  }
1419  mutt_str_copy(buf, mdata->group, buflen);
1420  break;
1421  }
1422 }
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition: mailbox.h:52
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:78
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
+ Here is the call graph for this function:
+ Here is the caller graph for this function: