NeoMutt  2025-12-11-980-ge38c27
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
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 <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 "expando/lib.h"
#include "store/lib.h"
#include "adata.h"
#include "edata.h"
#include "expando_newsrc.h"
#include "mdata.h"
#include "module_data.h"
#include "mutt_logging.h"
#include "mutt_socket.h"
#include "muttlib.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.
 
void nntp_acache_free (struct NntpMboxData *mdata)
 Remove all temporarily cache files.
 
void nntp_newsrc_close (struct NntpAccountData *adata)
 Unlock and close .newsrc file.
 
void nntp_group_unread_stat (struct NntpMboxData *mdata)
 Count number of unread articles using .newsrc data.
 
int nntp_newsrc_parse (struct NntpAccountData *adata)
 Parse .newsrc file.
 
void nntp_newsrc_gen_entries (struct Mailbox *m)
 Generate array of .newsrc entries.
 
static int update_file (char *filename, char *buf)
 Update file with new contents.
 
int nntp_newsrc_update (struct NntpAccountData *adata)
 Update .newsrc file.
 
static void cache_expand (char *dst, size_t dstlen, struct ConnAccount *cac, const char *src)
 Make fully qualified cache file name.
 
void nntp_expand_path (char *buf, size_t buflen, struct ConnAccount *cac)
 Make fully qualified url from newsgroup name.
 
int nntp_add_group (char *line, void *data)
 Parse newsgroup.
 
static int active_get_cache (struct NntpAccountData *adata)
 Load list of all newsgroups from cache.
 
int nntp_active_save_cache (struct NntpAccountData *adata)
 Save list of all newsgroups to cache.
 
static void nntp_hcache_namer (const struct StoreOps *store_ops, const char *path, struct Buffer *dest)
 Compose hcache file names - Implements hcache_namer_t -.
 
struct HeaderCachenntp_hcache_open (struct NntpMboxData *mdata)
 Open newsgroup hcache.
 
void nntp_hcache_update (struct NntpMboxData *mdata, struct HeaderCache *hc)
 Remove stale cached headers.
 
static int nntp_bcache_delete (const char *id, struct BodyCache *bcache, void *data)
 Delete an entry from the message cache - Implements bcache_list_t -.
 
void nntp_bcache_update (struct NntpMboxData *mdata)
 Remove stale cached messages.
 
void nntp_delete_group_cache (struct NntpMboxData *mdata)
 Remove hcache and bcache of newsgroup.
 
void nntp_clear_cache (struct NntpAccountData *adata)
 Clear the NNTP cache.
 
static const char * nntp_get_field (enum ConnAccountField field, void *gf_data)
 Get connection login credentials - Implements ConnAccount::get_field() -.
 
struct NntpAccountDatanntp_select_server (struct Mailbox *m, const char *server, bool leave_lock)
 Open a connection to an NNTP server.
 
void nntp_article_status (struct Mailbox *m, struct Email *e, char *group, anum_t anum)
 Get status of articles from .newsrc.
 
struct NntpMboxDatamutt_newsgroup_subscribe (struct NntpAccountData *adata, char *group)
 Subscribe newsgroup.
 
struct NntpMboxDatamutt_newsgroup_unsubscribe (struct NntpAccountData *adata, char *group)
 Unsubscribe newsgroup.
 
struct NntpMboxDatamutt_newsgroup_catchup (struct Mailbox *m, struct NntpAccountData *adata, char *group)
 Catchup newsgroup.
 
struct NntpMboxDatamutt_newsgroup_uncatchup (struct Mailbox *m, struct NntpAccountData *adata, char *group)
 Uncatchup newsgroup.
 
void nntp_mailbox (struct Mailbox *m, char *buf, size_t buflen)
 Get first newsgroup with new messages.
 

Detailed Description

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

Authors
  • Richard Russon
  • Pietro Cerutti
  • Ian Zimmerman
  • Ramkumar Ramachandra
  • Tóth János

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 75 of file newsrc.c.

76{
78 if (mdata)
79 return mdata;
80
81 size_t len = strlen(group) + 1;
82 /* create NntpMboxData structure and add it to hash */
83 mdata = mutt_mem_calloc(1, sizeof(struct NntpMboxData) + len);
84 mdata->group = (char *) mdata + sizeof(struct NntpMboxData);
85 mutt_str_copy(mdata->group, group, len);
86 mdata->adata = adata;
87 mdata->deleted = true;
89
90 /* add NntpMboxData to list */
92 {
93 adata->groups_max *= 2;
95 }
97
98 return mdata;
99}
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:338
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:365
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition memory.c:79
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition memory.h:55
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:587
void * mdata
Driver specific data.
Definition mailbox.h:134
struct HashTable * groups_hash
Hash Table: "newsgroup" -> NntpMboxData.
Definition adata.h:62
struct NntpMboxData ** groups_list
List of newsgroups.
Definition adata.h:60
unsigned int groups_num
Number of newsgroups.
Definition adata.h:58
unsigned int groups_max
Maximum number of newsgroups.
Definition adata.h:59
NNTP-specific Mailbox data -.
Definition mdata.h:34
char * group
Name of newsgroup.
Definition mdata.h:35
struct NntpAccountData * adata
Account data.
Definition mdata.h:48
+ 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 105 of file newsrc.c.

106{
107 for (int i = 0; i < NNTP_ACACHE_LEN; i++)
108 {
109 if (mdata->acache[i].path)
110 {
111 unlink(mdata->acache[i].path);
112 FREE(&mdata->acache[i].path);
113 }
114 }
115}
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define NNTP_ACACHE_LEN
Definition lib.h:85
char * path
Cache path.
Definition lib.h:72
struct NntpAcache acache[NNTP_ACACHE_LEN]
Article cache.
Definition mdata.h:49
+ 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 121 of file newsrc.c.

122{
123 if (!adata->fp_newsrc)
124 return;
125
126 mutt_debug(LL_DEBUG1, "Unlocking %s\n", adata->newsrc_file);
127 mutt_file_unlock(fileno(adata->fp_newsrc));
129}
int mutt_file_unlock(int fd)
Unlock a file previously locked by mutt_file_lock()
Definition file.c:1136
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
FILE * fp_newsrc
Newsrc file handle.
Definition adata.h:50
char * newsrc_file
Newsrc file path.
Definition adata.h:51
+ 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 135 of file newsrc.c.

136{
137 mdata->unread = 0;
138 if ((mdata->last_message == 0) ||
139 (mdata->first_message > mdata->last_message) || !mdata->newsrc_ent)
140 {
141 return;
142 }
143
144 mdata->unread = mdata->last_message - mdata->first_message + 1;
145 for (unsigned int i = 0; i < mdata->newsrc_len; i++)
146 {
147 anum_t first = mdata->newsrc_ent[i].first;
148 if (first < mdata->first_message)
149 first = mdata->first_message;
150 anum_t last = mdata->newsrc_ent[i].last;
151 if (last > mdata->last_message)
152 last = mdata->last_message;
153 if (first <= last)
154 mdata->unread -= last - first + 1;
155 }
156}
#define anum_t
Definition lib.h:63
anum_t last
Last article number in run.
Definition lib.h:81
anum_t first
First article number in run.
Definition lib.h:80
anum_t last_message
Last article number.
Definition mdata.h:38
struct NewsrcEntry * newsrc_ent
Newsrc entries.
Definition mdata.h:47
anum_t unread
Unread articles.
Definition mdata.h:41
unsigned int newsrc_len
Length of newsrc entry.
Definition mdata.h:46
anum_t first_message
First article number.
Definition mdata.h:37
+ 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 165 of file newsrc.c.

166{
167 if (!adata)
168 return -1;
169
170 char *line = NULL;
171 struct stat st = { 0 };
172
173 if (adata->fp_newsrc)
174 {
175 /* if we already have a handle, close it and reopen */
177 }
178 else
179 {
180 /* if file doesn't exist, create it */
181 adata->fp_newsrc = mutt_file_fopen(adata->newsrc_file, "a");
183 }
184
185 /* open .newsrc */
186 adata->fp_newsrc = mutt_file_fopen(adata->newsrc_file, "r");
187 if (!adata->fp_newsrc)
188 {
189 mutt_perror("%s", adata->newsrc_file);
190 return -1;
191 }
192
193 /* lock it */
194 mutt_debug(LL_DEBUG1, "Locking %s\n", adata->newsrc_file);
195 if (mutt_file_lock(fileno(adata->fp_newsrc), false, true) != 0)
196 {
198 return -1;
199 }
200
201 if (stat(adata->newsrc_file, &st) != 0)
202 {
203 mutt_perror("%s", adata->newsrc_file);
204 nntp_newsrc_close(adata);
205 return -1;
206 }
207
208 if ((adata->size == st.st_size) && (adata->mtime == st.st_mtime))
209 return 0;
210
211 adata->size = st.st_size;
212 adata->mtime = st.st_mtime;
213 adata->newsrc_modified = true;
214 mutt_debug(LL_DEBUG1, "Parsing %s\n", adata->newsrc_file);
215
216 /* .newsrc has been externally modified or hasn't been loaded yet */
217 for (unsigned int i = 0; i < adata->groups_num; i++)
218 {
219 struct NntpMboxData *mdata = adata->groups_list[i];
220 if (!mdata)
221 continue;
222
223 mdata->subscribed = false;
224 mdata->newsrc_len = 0;
225 FREE(&mdata->newsrc_ent);
226 }
227
228 line = MUTT_MEM_MALLOC(st.st_size + 1, char);
229 while (st.st_size && fgets(line, st.st_size + 1, adata->fp_newsrc))
230 {
231 char *b = NULL;
232 char *h = NULL;
233 unsigned int j = 1;
234 bool subs = false;
235
236 /* find end of newsgroup name */
237 char *p = strpbrk(line, ":!");
238 if (!p)
239 continue;
240
241 /* ":" - subscribed, "!" - unsubscribed */
242 if (*p == ':')
243 subs = true;
244 *p++ = '\0';
245
246 /* get newsgroup data */
247 struct NntpMboxData *mdata = mdata_find(adata, line);
248 FREE(&mdata->newsrc_ent);
249
250 /* count number of entries */
251 b = p;
252 while (*b)
253 if (*b++ == ',')
254 j++;
255 mdata->newsrc_ent = MUTT_MEM_CALLOC(j, struct NewsrcEntry);
256 mdata->subscribed = subs;
257
258 /* parse entries */
259 j = 0;
260 while (p)
261 {
262 b = p;
263
264 /* find end of entry */
265 p = strchr(p, ',');
266 if (p)
267 *p++ = '\0';
268
269 /* first-last or single number */
270 h = strchr(b, '-');
271 if (h)
272 *h++ = '\0';
273 else
274 h = b;
275
276 if ((sscanf(b, ANUM_FMT, &mdata->newsrc_ent[j].first) == 1) &&
277 (sscanf(h, ANUM_FMT, &mdata->newsrc_ent[j].last) == 1))
278 {
279 j++;
280 }
281 }
282 if (j == 0)
283 {
284 mdata->newsrc_ent[j].first = 1;
285 mdata->newsrc_ent[j].last = 0;
286 j++;
287 }
288 if (mdata->last_message == 0)
289 mdata->last_message = mdata->newsrc_ent[j - 1].last;
290 mdata->newsrc_len = j;
291 MUTT_MEM_REALLOC(&mdata->newsrc_ent, j, struct NewsrcEntry);
293 mutt_debug(LL_DEBUG2, "%s\n", mdata->group);
294 }
295 FREE(&line);
296 return 1;
297}
int mutt_file_lock(int fd, bool excl, bool timeout)
(Try to) Lock a file using fcntl()
Definition file.c:1088
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
#define mutt_perror(...)
Definition logging2.h:95
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
#define MUTT_MEM_MALLOC(n, type)
Definition memory.h:53
void nntp_newsrc_close(struct NntpAccountData *adata)
Unlock and close .newsrc file.
Definition newsrc.c:121
static struct NntpMboxData * mdata_find(struct NntpAccountData *adata, const char *group)
Find NntpMboxData for given newsgroup or add it.
Definition newsrc.c:75
void nntp_group_unread_stat(struct NntpMboxData *mdata)
Count number of unread articles using .newsrc data.
Definition newsrc.c:135
#define ANUM_FMT
Definition lib.h:64
An entry in a .newsrc (subscribed newsgroups)
Definition lib.h:79
bool newsrc_modified
Newsrc file was modified.
Definition adata.h:49
off_t size
Newsrc file size.
Definition adata.h:54
time_t mtime
Newsrc modification time.
Definition adata.h:55
bool subscribed
Subscribed to this newsgroup.
Definition mdata.h:42
+ 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 303 of file newsrc.c.

304{
305 if (!m)
306 return;
307
308 struct NntpMboxData *mdata = m->mdata;
309 anum_t last = 0;
310 anum_t first = 1;
311 bool series;
312 unsigned int entries;
313
314 const enum EmailSortType c_sort = cs_subset_sort(NeoMutt->sub, "sort");
315 if (c_sort != EMAIL_SORT_UNSORTED)
316 {
319 }
320
321 entries = mdata->newsrc_len;
322 if (!entries)
323 {
324 entries = 5;
325 mdata->newsrc_ent = MUTT_MEM_CALLOC(entries, struct NewsrcEntry);
326 }
327
328 /* Set up to fake initial sequence from 1 to the article before the
329 * first article in our list */
330 mdata->newsrc_len = 0;
331 series = true;
332 for (int i = 0; i < m->msg_count; i++)
333 {
334 struct Email *e = m->emails[i];
335 if (!e)
336 break;
337
338 /* search for first unread */
339 if (series)
340 {
341 /* We don't actually check sequential order, since we mark
342 * "missing" entries as read/deleted */
343 last = nntp_edata_get(e)->article_num;
344 if ((last >= mdata->first_message) && !e->deleted && !e->read)
345 {
346 if (mdata->newsrc_len >= entries)
347 {
348 entries *= 2;
349 MUTT_MEM_REALLOC(&mdata->newsrc_ent, entries, struct NewsrcEntry);
350 }
351 mdata->newsrc_ent[mdata->newsrc_len].first = first;
352 mdata->newsrc_ent[mdata->newsrc_len].last = last - 1;
353 mdata->newsrc_len++;
354 series = false;
355 }
356 }
357 else
358 {
359 /* search for first read */
360 if (e->deleted || e->read)
361 {
362 first = last + 1;
363 series = true;
364 }
365 last = nntp_edata_get(e)->article_num;
366 }
367 }
368
369 if (series && (first <= mdata->last_loaded))
370 {
371 if (mdata->newsrc_len >= entries)
372 {
373 entries++;
374 MUTT_MEM_REALLOC(&mdata->newsrc_ent, entries, struct NewsrcEntry);
375 }
376 mdata->newsrc_ent[mdata->newsrc_len].first = first;
377 mdata->newsrc_ent[mdata->newsrc_len].last = mdata->last_loaded;
378 mdata->newsrc_len++;
379 }
380 MUTT_MEM_REALLOC(&mdata->newsrc_ent, mdata->newsrc_len, struct NewsrcEntry);
381
382 if (c_sort != EMAIL_SORT_UNSORTED)
383 {
384 cs_subset_str_native_set(NeoMutt->sub, "sort", c_sort, NULL);
386 }
387}
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition helpers.c:266
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition mailbox.c:232
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition mailbox.h:183
EmailSortType
Methods for sorting Emails.
Definition sort.h:53
@ EMAIL_SORT_UNSORTED
Sort by the order the messages appear in the mailbox.
Definition sort.h:64
struct NntpEmailData * nntp_edata_get(struct Email *e)
Get the private data for this Email.
Definition edata.c:60
The envelope/body of an email.
Definition email.h:39
bool read
Email is read.
Definition email.h:50
bool deleted
Email is deleted.
Definition email.h:78
int msg_count
Total number of messages.
Definition mailbox.h:90
struct Email ** emails
Array of Emails.
Definition mailbox.h:98
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
anum_t article_num
NNTP article number.
Definition edata.h:36
anum_t last_loaded
Last loaded article.
Definition mdata.h:39
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:303
+ Here is the call graph for this function:
+ Here is the caller 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 396 of file newsrc.c.

397{
398 FILE *fp = NULL;
399 char tempfile[PATH_MAX] = { 0 };
400 int rc = -1;
401
402 while (true)
403 {
404 snprintf(tempfile, sizeof(tempfile), "%s.tmp", filename);
405 fp = mutt_file_fopen(tempfile, "w");
406 if (!fp)
407 {
408 mutt_perror("%s", tempfile);
409 *tempfile = '\0';
410 break;
411 }
412 if (fputs(buf, fp) == EOF)
413 {
414 mutt_perror("%s", tempfile);
415 break;
416 }
417 if (mutt_file_fclose(&fp) == EOF)
418 {
419 mutt_perror("%s", tempfile);
420 fp = NULL;
421 break;
422 }
423 fp = NULL;
424 if (rename(tempfile, filename) < 0)
425 {
426 mutt_perror("%s", filename);
427 break;
428 }
429 *tempfile = '\0';
430 rc = 0;
431 break;
432 }
433 mutt_file_fclose(&fp);
434
435 if (*tempfile)
436 unlink(tempfile);
437 return rc;
438}
#define PATH_MAX
Definition mutt.h:49
+ 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 446 of file newsrc.c.

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

528{
529 char file[PATH_MAX] = { 0 };
530
531 /* server subdirectory */
532 struct Url url = { 0 };
533 account_to_url(cac, &url);
534 url.path = mutt_str_dup(src);
535 url_tostring(&url, file, sizeof(file), U_PATH);
536 FREE(&url.path);
537
538 /* remove trailing slash */
539 char *c = file + strlen(file) - 1;
540 if (*c == '/')
541 *c = '\0';
542
543 struct Buffer *tmp = buf_pool_get();
544 buf_addstr(tmp, file);
545 mutt_encode_path(tmp, file);
546
547 const char *const c_news_cache_dir = cs_subset_path(NeoMutt->sub, "news_cache_dir");
548 snprintf(dst, dstlen, "%s/%s", c_news_cache_dir, buf_string(tmp));
549
550 buf_pool_release(&tmp);
551}
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:233
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
void account_to_url(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
void mutt_encode_path(struct Buffer *buf, const char *src)
Convert a path to 'us-ascii'.
Definition muttlib.c:803
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
String manipulation buffer.
Definition buffer.h:36
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(const struct Url *url, char *dest, size_t len, uint8_t flags)
Output the URL string for a given Url object.
Definition url.c:426
#define U_PATH
Path is included in URL.
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 559 of file newsrc.c.

560{
561 struct Url url = { 0 };
562
563 account_to_url(cac, &url);
564 url.path = mutt_str_dup(buf);
565 url_tostring(&url, buf, buflen, U_NONE);
566 FREE(&url.path);
567}
#define U_NONE
No flags are set for URL parsing.
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 575 of file newsrc.c.

576{
577 struct NntpAccountData *adata = data;
578 struct NntpMboxData *mdata = NULL;
579 char group[1024] = { 0 };
580 char desc[8192] = { 0 };
581 char mod = '\0';
582 anum_t first = 0;
583 anum_t last = 0;
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_FMT " " ANUM_FMT " %c %8191[^\n]", group,
590 &last, &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:284
void * adata
Private data (for Mailbox backends)
Definition account.h:42
NNTP-specific Account data -.
Definition adata.h:36
char * desc
Description of newsgroup.
Definition mdata.h:36
+ 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] = { 0 };
620 char file[4096] = { 0 };
621 time_t t = 0;
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 logging2.h:93
#define _(a)
Definition message.h:28
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
int nntp_add_group(char *line, void *data)
Parse newsgroup.
Definition newsrc.c:575
static void cache_expand(char *dst, size_t dstlen, struct ConnAccount *cac, const char *src)
Make fully qualified cache file name.
Definition newsrc.c:527
struct ConnAccount account
Account details: username, password, etc.
Definition connection.h:49
time_t newgroups_time
Last newgroups request time.
Definition adata.h:56
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(buflen, char);
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, char);
672 }
673 snprintf(buf + off, buflen - off, "%s " ANUM_FMT " " ANUM_FMT " %c%s%s\n",
674 mdata->group, mdata->last_message, mdata->first_message,
675 mdata->allowed ? 'y' : 'n', mdata->desc ? " " : "",
676 mdata->desc ? mdata->desc : "");
677 off += strlen(buf + off);
678 }
679
680 char file[PATH_MAX] = { 0 };
681 cache_expand(file, sizeof(file), &adata->conn->account, ".active");
682 mutt_debug(LL_DEBUG1, "Updating %s\n", file);
683 int rc = update_file(file, buf);
684 FREE(&buf);
685 return rc;
686}
bool cacheable
Can be cached.
Definition adata.h:48
+ 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 712 of file newsrc.c.

713{
714 struct Url url = { 0 };
715 char file[PATH_MAX] = { 0 };
716
717 const bool c_save_unsubscribed = cs_subset_bool(NeoMutt->sub, "save_unsubscribed");
718 if (!mdata->adata || !mdata->adata->cacheable || !mdata->adata->conn || !mdata->group ||
719 !(mdata->newsrc_ent || mdata->subscribed || c_save_unsubscribed))
720 {
721 return NULL;
722 }
723
724 account_to_url(&mdata->adata->conn->account, &url);
725 url.path = mdata->group;
726 url_tostring(&url, file, sizeof(file), U_PATH);
727 const char *const c_news_cache_dir = cs_subset_path(NeoMutt->sub, "news_cache_dir");
728 return hcache_open(c_news_cache_dir, file, nntp_hcache_namer, true);
729}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
static void nntp_hcache_namer(const struct StoreOps *store_ops, const char *path, struct Buffer *dest)
Compose hcache file names - Implements hcache_namer_t -.
Definition newsrc.c:692
struct HeaderCache * hcache_open(const char *path, const char *folder, hcache_namer_t namer, bool create)
Multiplexor for StoreOps::open.
Definition hcache.c:492
+ 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] = { 0 };
742 bool old = false;
743 anum_t first = 0;
744 anum_t last = 0;
745
746 /* fetch previous values of first and last */
747 char *hdata = hcache_fetch_raw_str(hc, "index", 5);
748 if (hdata)
749 {
750 mutt_debug(LL_DEBUG2, "hcache_fetch_email index: %s\n", hdata);
751 if (sscanf(hdata, ANUM_FMT " " ANUM_FMT, &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), ANUM_FMT, current);
763 mutt_debug(LL_DEBUG2, "hcache_delete_email %s\n", buf);
764 hcache_delete_email(hc, buf, strlen(buf));
765 }
766 }
767 FREE(&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), ANUM_FMT " " ANUM_FMT, mdata->first_message,
774 mdata->last_message);
775 mutt_debug(LL_DEBUG2, "hcache_store_email index: %s\n", buf);
776 hcache_store_raw(hc, "index", 5, buf, strlen(buf) + 1);
777 }
778}
int hcache_delete_email(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition hcache.c:769
char * hcache_fetch_raw_str(struct HeaderCache *hc, const char *key, size_t keylen)
Fetch a string from the cache.
Definition hcache.c:679
int 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:754
anum_t last_cached
Last cached article.
Definition mdata.h:40
+ Here is the call graph for this function:
+ Here is the caller 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 805 of file newsrc.c.

806{
808}
int mutt_bcache_list(struct BodyCache *bcache, bcache_list_t want_id, void *data)
Find matching entries in the Body Cache.
Definition bcache.c:355
static int nntp_bcache_delete(const char *id, struct BodyCache *bcache, void *data)
Delete an entry from the message cache - Implements bcache_list_t -.
Definition newsrc.c:785
struct BodyCache * bcache
Body cache.
Definition mdata.h:50
+ Here is the call graph for this function:
+ Here is the caller 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 814 of file newsrc.c.

815{
816 if (!mdata || !mdata->adata || !mdata->adata->cacheable)
817 return;
818
819#ifdef USE_HCACHE
820 const char *const c_header_cache_backend = cs_subset_string(NeoMutt->sub, "header_cache_backend");
821 const struct StoreOps *store_ops = store_get_backend_ops(c_header_cache_backend);
822 if (store_ops)
823 {
824 struct Buffer *file = buf_pool_get();
825 nntp_hcache_namer(store_ops, mdata->group, file);
826 cache_expand(file->data, file->dsize, &mdata->adata->conn->account, buf_string(file));
827 unlink(buf_string(file));
828 mdata->last_cached = 0;
829 mutt_debug(LL_DEBUG2, "%s\n", buf_string(file));
830 buf_pool_release(&file);
831 }
832#endif
833
834 if (!mdata->bcache)
835 {
836 mdata->bcache = mutt_bcache_open(&mdata->adata->conn->account, mdata->group);
837 }
838 if (mdata->bcache)
839 {
840 mutt_debug(LL_DEBUG2, "%s/*\n", mdata->group);
842 mutt_bcache_close(&mdata->bcache);
843 }
844}
struct BodyCache * mutt_bcache_open(struct ConnAccount *account, const char *mailbox)
Open an Email-Body Cache.
Definition bcache.c:162
void mutt_bcache_close(struct BodyCache **ptr)
Close an Email-Body Cache.
Definition bcache.c:183
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
const struct StoreOps * store_get_backend_ops(const char *str)
Get the API functions for an store backend.
Definition store.c:88
size_t dsize
Length of data.
Definition buffer.h:39
char * data
Pointer to data.
Definition buffer.h:37
Definition lib.h:66
+ 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 852 of file newsrc.c.

853{
854 if (!adata || !adata->cacheable)
855 return;
856
857 struct dirent *de = NULL;
858 DIR *dir = NULL;
859 struct Buffer *cache = buf_pool_get();
860 struct Buffer *file = buf_pool_get();
861
862 cache_expand(cache->data, cache->dsize, &adata->conn->account, NULL);
863 buf_fix_dptr(cache);
865 if (!dir)
866 goto done;
867
868 buf_addch(cache, '/');
869 const bool c_save_unsubscribed = cs_subset_bool(NeoMutt->sub, "save_unsubscribed");
870
871 while ((de = readdir(dir)))
872 {
873 char *group = de->d_name;
874 if (mutt_str_equal(group, ".") || mutt_str_equal(group, ".."))
875 continue;
876
877 buf_printf(file, "%s%s", buf_string(cache), group);
878 struct stat st = { 0 };
879 if (stat(buf_string(file), &st) != 0)
880 continue;
881
882#ifdef USE_HCACHE
883 if (S_ISREG(st.st_mode))
884 {
885 char *ext = group + strlen(group) - 7;
886 if ((strlen(group) < 8) || !mutt_str_equal(ext, ".hcache"))
887 continue;
888 *ext = '\0';
889 }
890 else
891#endif
892 if (!S_ISDIR(st.st_mode))
893 continue;
894
895 struct NntpMboxData tmp_mdata = { 0 };
897 if (!mdata)
898 {
899 mdata = &tmp_mdata;
900 mdata->adata = adata;
901 mdata->group = group;
902 mdata->bcache = NULL;
903 }
904 else if (mdata->newsrc_ent || mdata->subscribed || c_save_unsubscribed)
905 {
906 continue;
907 }
908
910 if (S_ISDIR(st.st_mode))
911 {
912 rmdir(buf_string(file));
913 mutt_debug(LL_DEBUG2, "%s\n", buf_string(file));
914 }
915 }
916 closedir(dir);
917
918done:
919 buf_pool_release(&cache);
920 buf_pool_release(&file);
921}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:168
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition buffer.c:189
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:248
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition file.c:535
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition file.h:68
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:666
void nntp_delete_group_cache(struct NntpMboxData *mdata)
Remove hcache and bcache of newsgroup.
Definition newsrc.c:814
+ 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.

See also
$newsrc

Definition at line 957 of file newsrc.c.

958{
959 char file[PATH_MAX] = { 0 };
960 int rc;
961 struct ConnAccount cac = { { 0 } };
962 struct NntpAccountData *adata = NULL;
963 struct Connection *conn = NULL;
964
965 if (!server || (*server == '\0'))
966 {
967 mutt_error(_("No news server defined"));
968 return NULL;
969 }
970
971 /* create account from news server url */
972 cac.flags = 0;
973 cac.port = NNTP_PORT;
975 cac.service = "nntp";
977
978 snprintf(file, sizeof(file), "%s%s", strstr(server, "://") ? "" : "news://", server);
979 struct Url *url = url_parse(file);
980 if (!url || (url->path && *url->path) ||
981 !((url->scheme == U_NNTP) || (url->scheme == U_NNTPS)) || !url->host ||
982 (account_from_url(&cac, url) < 0))
983 {
984 url_free(&url);
985 mutt_error(_("%s is an invalid news server specification"), server);
986 return NULL;
987 }
988 if (url->scheme == U_NNTPS)
989 {
990 cac.flags |= MUTT_ACCT_SSL;
991 cac.port = NNTP_SSL_PORT;
992 }
993 url_free(&url);
994
995 // If nntp_user and nntp_pass are specified in the config, use them to find the connection
996 const char *user = NULL;
997 const char *pass = NULL;
998 if ((user = cac.get_field(MUTT_CA_USER, NULL)))
999 {
1000 mutt_str_copy(cac.user, user, sizeof(cac.user));
1001 cac.flags |= MUTT_ACCT_USER;
1002 }
1003 if ((pass = cac.get_field(MUTT_CA_PASS, NULL)))
1004 {
1005 mutt_str_copy(cac.pass, pass, sizeof(cac.pass));
1006 cac.flags |= MUTT_ACCT_PASS;
1007 }
1008
1009 /* find connection by account */
1010 conn = mutt_conn_find(&cac);
1011 if (!conn)
1012 return NULL;
1013 if (!(conn->account.flags & MUTT_ACCT_USER) && cac.flags & MUTT_ACCT_USER)
1014 {
1015 conn->account.flags |= MUTT_ACCT_USER;
1016 conn->account.user[0] = '\0';
1017 }
1018
1019 /* new news server */
1020 adata = nntp_adata_new(conn);
1021
1022 rc = nntp_open_connection(adata);
1023
1024 /* try to create cache directory and enable caching */
1025 adata->cacheable = false;
1026 const char *const c_news_cache_dir = cs_subset_path(NeoMutt->sub, "news_cache_dir");
1027 if ((rc >= 0) && c_news_cache_dir)
1028 {
1029 cache_expand(file, sizeof(file), &conn->account, NULL);
1030 if (mutt_file_mkdir(file, S_IRWXU) < 0)
1031 {
1032 mutt_error(_("Can't create %s: %s"), file, strerror(errno));
1033 }
1034 adata->cacheable = true;
1035 }
1036
1037 /* load .newsrc */
1038 if (rc >= 0)
1039 {
1040 const struct Expando *c_newsrc = cs_subset_expando(NeoMutt->sub, "newsrc");
1041 struct Buffer *buf = buf_pool_get();
1043 buf->dsize, NeoMutt->env, buf);
1044 expand_path(buf, false);
1045 adata->newsrc_file = buf_strdup(buf);
1046 buf_pool_release(&buf);
1047 rc = nntp_newsrc_parse(adata);
1048 }
1049 if (rc >= 0)
1050 {
1051 /* try to load list of newsgroups from cache */
1052 if (adata->cacheable && (active_get_cache(adata) == 0))
1053 {
1054 rc = nntp_check_new_groups(m, adata);
1055 }
1056 else
1057 {
1058 /* load list of newsgroups from server */
1059 rc = nntp_active_fetch(adata, false);
1060 }
1061 }
1062
1063 if (rc >= 0)
1064 nntp_clear_cache(adata);
1065
1066#ifdef USE_HCACHE
1067 /* check cache files */
1068 if ((rc >= 0) && adata->cacheable)
1069 {
1070 struct dirent *de = NULL;
1071 DIR *dir = mutt_file_opendir(file, MUTT_OPENDIR_NONE);
1072
1073 if (dir)
1074 {
1075 while ((de = readdir(dir)))
1076 {
1077 struct HeaderCache *hc = NULL;
1078 char *group = de->d_name;
1079
1080 char *p = group + strlen(group) - 7;
1081 if ((strlen(group) < 8) || !mutt_str_equal(p, ".hcache"))
1082 continue;
1083 *p = '\0';
1085 if (!mdata)
1086 continue;
1087
1088 hc = nntp_hcache_open(mdata);
1089 if (!hc)
1090 continue;
1091
1092 /* fetch previous values of first and last */
1093 char *hdata = hcache_fetch_raw_str(hc, "index", 5);
1094 if (hdata)
1095 {
1096 anum_t first = 0;
1097 anum_t last = 0;
1098
1099 if (sscanf(hdata, ANUM_FMT " " ANUM_FMT, &first, &last) == 2)
1100 {
1101 if (mdata->deleted)
1102 {
1103 mdata->first_message = first;
1104 mdata->last_message = last;
1105 }
1106 if ((last >= mdata->first_message) && (last <= mdata->last_message))
1107 {
1108 mdata->last_cached = last;
1109 mutt_debug(LL_DEBUG2, "%s last_cached=" ANUM_FMT "\n", mdata->group, last);
1110 }
1111 }
1112 FREE(&hdata);
1113 }
1114 hcache_close(&hc);
1115 }
1116 closedir(dir);
1117 }
1118 }
1119#endif
1120
1121 if ((rc < 0) || !leave_lock)
1123
1124 if (rc < 0)
1125 {
1130 FREE(&adata);
1131 mutt_socket_close(conn);
1132 FREE(&conn);
1133 return NULL;
1134 }
1135
1136 return adata;
1137}
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
const struct Expando * cs_subset_expando(const struct ConfigSubset *sub, const char *name)
Get an Expando config item by name.
@ MUTT_CA_USER
User name.
Definition connaccount.h:36
@ MUTT_CA_PASS
Password.
Definition connaccount.h:37
@ MUTT_ACCT_SSL
Account uses SSL/TLS.
Definition connaccount.h:51
@ MUTT_ACCT_PASS
Password field has been set.
Definition connaccount.h:50
@ MUTT_ACCT_USER
User field has been set.
Definition connaccount.h:48
int expando_filter(const struct Expando *exp, const struct ExpandoRenderCallback *erc, void *data, MuttFormatFlags flags, int max_cols, char **env_list, struct Buffer *buf)
Render an Expando and run the result through a filter.
Definition filter.c:139
const struct ExpandoRenderCallback NntpRenderCallbacks[]
Callbacks for Newsrc Expandos.
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition file.c:844
static const char * nntp_get_field(enum ConnAccountField field, void *gf_data)
Get connection login credentials - Implements ConnAccount::get_field() -.
Definition newsrc.c:926
#define mutt_error(...)
Definition logging2.h:94
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition hash.c:460
void hcache_close(struct HeaderCache **ptr)
Multiplexor for StoreOps::close.
Definition hcache.c:564
int account_from_url(struct ConnAccount *cac, const struct Url *url)
Fill ConnAccount with information from url.
@ MUTT_ACCT_TYPE_NNTP
Nntp (Usenet) Account.
struct Connection * mutt_conn_find(const struct ConnAccount *cac)
Find a connection from a list.
Definition mutt_socket.c:88
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:122
struct HeaderCache * nntp_hcache_open(struct NntpMboxData *mdata)
Open newsgroup hcache.
Definition newsrc.c:712
void nntp_clear_cache(struct NntpAccountData *adata)
Clear the NNTP cache.
Definition newsrc.c:852
int nntp_newsrc_parse(struct NntpAccountData *adata)
Parse .newsrc file.
Definition newsrc.c:165
static int active_get_cache(struct NntpAccountData *adata)
Load list of all newsgroups from cache.
Definition newsrc.c:617
struct NntpAccountData * nntp_adata_new(struct Connection *conn)
Allocate and initialise a new NntpAccountData structure.
Definition adata.c:65
int nntp_active_fetch(struct NntpAccountData *adata, bool mark_new)
Fetch list of all newsgroups from server.
Definition nntp.c:2044
#define NNTP_SSL_PORT
Definition private.h:37
#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:2112
int nntp_open_connection(struct NntpAccountData *adata)
Connect to server, authenticate and get capabilities.
Definition nntp.c:1772
@ MUTT_FORMAT_NONE
No flags are set.
Definition render.h:37
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition socket.c:100
Login details for a remote server.
Definition connaccount.h:59
char user[128]
Username.
Definition connaccount.h:62
char pass[256]
Password.
Definition connaccount.h:63
const char * service
Name of the service, e.g. "imap".
Definition connaccount.h:67
const char *(* get_field)(enum ConnAccountField field, void *gf_data)
Definition connaccount.h:76
unsigned char type
Connection type, e.g. MUTT_ACCT_TYPE_IMAP.
Definition connaccount.h:65
MuttAccountFlags flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition connaccount.h:66
unsigned short port
Port to connect to.
Definition connaccount.h:64
Parsed Expando trees.
Definition expando.h:41
Header Cache.
Definition lib.h:87
char ** env
Private copy of the environment variables.
Definition neomutt.h:57
char * authenticators
Authenticators list.
Definition adata.h:52
char * user
Username.
Definition url.h:71
char * host
Host.
Definition url.h:73
char * pass
Password.
Definition url.h:72
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:242
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition url.c:124
@ 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 1151 of file newsrc.c.

1152{
1153 struct NntpMboxData *mdata = m->mdata;
1154
1155 if (group)
1156 mdata = mutt_hash_find(mdata->adata->groups_hash, group);
1157
1158 if (!mdata)
1159 return;
1160
1161 for (unsigned int i = 0; i < mdata->newsrc_len; i++)
1162 {
1163 if ((anum >= mdata->newsrc_ent[i].first) && (anum <= mdata->newsrc_ent[i].last))
1164 {
1165 /* can't use mutt_set_flag() because mview_update() didn't get called yet */
1166 e->read = true;
1167 return;
1168 }
1169 }
1170
1171 /* article was not cached yet, it's new */
1172 if (anum > mdata->last_cached)
1173 return;
1174
1175 /* article isn't read but cached, it's old */
1176 const bool c_mark_old = cs_subset_bool(NeoMutt->sub, "mark_old");
1177 if (c_mark_old)
1178 e->old = true;
1179}
bool old
Email is seen, but unread.
Definition email.h:49
+ 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 1188 of file newsrc.c.

1189{
1190 if (!adata || !adata->groups_hash || !group || (*group == '\0'))
1191 return NULL;
1192
1194 mdata->subscribed = true;
1195 if (!mdata->newsrc_ent)
1196 {
1197 mdata->newsrc_ent = MUTT_MEM_CALLOC(1, struct NewsrcEntry);
1198 mdata->newsrc_len = 1;
1199 mdata->newsrc_ent[0].first = 1;
1200 mdata->newsrc_ent[0].last = 0;
1201 }
1202 return mdata;
1203}
+ 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 1212 of file newsrc.c.

1213{
1214 if (!adata || !adata->groups_hash || !group || (*group == '\0'))
1215 return NULL;
1216
1218 if (!mdata)
1219 return NULL;
1220
1221 mdata->subscribed = false;
1222 const bool c_save_unsubscribed = cs_subset_bool(NeoMutt->sub, "save_unsubscribed");
1223 if (!c_save_unsubscribed)
1224 {
1225 mdata->newsrc_len = 0;
1226 FREE(&mdata->newsrc_ent);
1227 }
1228 return mdata;
1229}
+ 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 1239 of file newsrc.c.

1241{
1242 if (!adata || !adata->groups_hash || !group || (*group == '\0'))
1243 return NULL;
1244
1246 if (!mdata)
1247 return NULL;
1248
1249 if (mdata->newsrc_ent)
1250 {
1251 MUTT_MEM_REALLOC(&mdata->newsrc_ent, 1, struct NewsrcEntry);
1252 mdata->newsrc_len = 1;
1253 mdata->newsrc_ent[0].first = 1;
1254 mdata->newsrc_ent[0].last = mdata->last_message;
1255 }
1256 mdata->unread = 0;
1257 if (m && (m->mdata == mdata))
1258 {
1259 for (unsigned int i = 0; i < m->msg_count; i++)
1260 {
1261 struct Email *e = m->emails[i];
1262 if (!e)
1263 break;
1264 mutt_set_flag(m, e, MUTT_READ, true, true);
1265 }
1266 }
1267 return mdata;
1268}
void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
Definition flags.c:54
@ MUTT_READ
Messages that have been read.
Definition mutt.h:92
+ 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 1278 of file newsrc.c.

1280{
1281 if (!adata || !adata->groups_hash || !group || (*group == '\0'))
1282 return NULL;
1283
1285 if (!mdata)
1286 return NULL;
1287
1288 if (mdata->newsrc_ent)
1289 {
1290 MUTT_MEM_REALLOC(&mdata->newsrc_ent, 1, struct NewsrcEntry);
1291 mdata->newsrc_len = 1;
1292 mdata->newsrc_ent[0].first = 1;
1293 mdata->newsrc_ent[0].last = mdata->first_message - 1;
1294 }
1295 if (m && (m->mdata == mdata))
1296 {
1297 mdata->unread = m->msg_count;
1298 for (unsigned int i = 0; i < m->msg_count; i++)
1299 {
1300 struct Email *e = m->emails[i];
1301 if (!e)
1302 break;
1303 mutt_set_flag(m, e, MUTT_READ, false, true);
1304 }
1305 }
1306 else
1307 {
1308 mdata->unread = mdata->last_message;
1309 if (mdata->newsrc_ent)
1310 mdata->unread -= mdata->newsrc_ent[0].last;
1311 }
1312 return mdata;
1313}
+ 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 1321 of file newsrc.c.

1322{
1323 if (!m)
1324 return;
1325
1327 for (unsigned int i = 0; i < mod_data->current_news_srv->groups_num; i++)
1328 {
1329 struct NntpMboxData *mdata = mod_data->current_news_srv->groups_list[i];
1330
1331 if (!mdata || !mdata->subscribed || !mdata->unread)
1332 continue;
1333
1334 if ((m->type == MUTT_NNTP) &&
1335 mutt_str_equal(mdata->group, ((struct NntpMboxData *) m->mdata)->group))
1336 {
1337 unsigned int unread = 0;
1338
1339 for (unsigned int j = 0; j < m->msg_count; j++)
1340 {
1341 struct Email *e = m->emails[j];
1342 if (!e)
1343 break;
1344 if (!e->read && !e->deleted)
1345 unread++;
1346 }
1347 if (unread == 0)
1348 continue;
1349 }
1350 mutt_str_copy(buf, mdata->group, buflen);
1351 break;
1352 }
1353}
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition mailbox.h:48
@ MODULE_ID_NNTP
ModuleNntp, Nntp
Definition module_api.h:83
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:666
enum MailboxType type
Mailbox type.
Definition mailbox.h:104
Nntp private Module data.
Definition module_data.h:30
struct NntpAccountData * current_news_srv
Current NNTP news server.
Definition module_data.h:32
+ Here is the call graph for this function:
+ Here is the caller graph for this function: