NeoMutt  2024-11-14-138-ge5ca67
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 "adata.h"
#include "edata.h"
#include "expando_newsrc.h"
#include "mdata.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.
 
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 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 74 of file newsrc.c.

75{
77 if (mdata)
78 return mdata;
79
80 size_t len = strlen(group) + 1;
81 /* create NntpMboxData structure and add it to hash */
82 mdata = mutt_mem_calloc(1, sizeof(struct NntpMboxData) + len);
83 mdata->group = (char *) mdata + sizeof(struct NntpMboxData);
84 mutt_str_copy(mdata->group, group, len);
85 mdata->adata = adata;
86 mdata->deleted = true;
88
89 /* add NntpMboxData to list */
91 {
92 adata->groups_max *= 2;
94 }
96
97 return mdata;
98}
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:76
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition: memory.h:43
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:581
void * mdata
Driver specific data.
Definition: mailbox.h:132
struct HashTable * groups_hash
Hash Table: "newsgroup" -> NntpMboxData.
Definition: adata.h:61
struct NntpMboxData ** groups_list
Definition: adata.h:60
unsigned int groups_num
Definition: adata.h:58
unsigned int groups_max
Definition: adata.h:59
NNTP-specific Mailbox data -.
Definition: mdata.h:34
char * group
Name of newsgroup.
Definition: mdata.h:35
struct NntpAccountData * adata
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 104 of file newsrc.c.

105{
106 for (int i = 0; i < NNTP_ACACHE_LEN; i++)
107 {
108 if (mdata->acache[i].path)
109 {
110 unlink(mdata->acache[i].path);
111 FREE(&mdata->acache[i].path);
112 }
113 }
114}
#define FREE(x)
Definition: memory.h:55
#define NNTP_ACACHE_LEN
Definition: lib.h:84
char * path
Cache path.
Definition: lib.h:71
struct NntpAcache acache[NNTP_ACACHE_LEN]
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 120 of file newsrc.c.

121{
122 if (!adata->fp_newsrc)
123 return;
124
125 mutt_debug(LL_DEBUG1, "Unlocking %s\n", adata->newsrc_file);
126 mutt_file_unlock(fileno(adata->fp_newsrc));
128}
int mutt_file_unlock(int fd)
Unlock a file previously locked by mutt_file_lock()
Definition: file.c:1249
#define mutt_file_fclose(FP)
Definition: file.h:138
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
FILE * fp_newsrc
Definition: adata.h:50
char * newsrc_file
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 134 of file newsrc.c.

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

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

302{
303 if (!m)
304 return;
305
306 struct NntpMboxData *mdata = m->mdata;
307 anum_t last = 0, first = 1;
308 bool series;
309 unsigned int entries;
310
311 const enum EmailSortType c_sort = cs_subset_sort(NeoMutt->sub, "sort");
312 if (c_sort != EMAIL_SORT_UNSORTED)
313 {
316 }
317
318 entries = mdata->newsrc_len;
319 if (!entries)
320 {
321 entries = 5;
322 mdata->newsrc_ent = MUTT_MEM_CALLOC(entries, struct NewsrcEntry);
323 }
324
325 /* Set up to fake initial sequence from 1 to the article before the
326 * first article in our list */
327 mdata->newsrc_len = 0;
328 series = true;
329 for (int i = 0; i < m->msg_count; i++)
330 {
331 struct Email *e = m->emails[i];
332 if (!e)
333 break;
334
335 /* search for first unread */
336 if (series)
337 {
338 /* We don't actually check sequential order, since we mark
339 * "missing" entries as read/deleted */
340 last = nntp_edata_get(e)->article_num;
341 if ((last >= mdata->first_message) && !e->deleted && !e->read)
342 {
343 if (mdata->newsrc_len >= entries)
344 {
345 entries *= 2;
346 MUTT_MEM_REALLOC(&mdata->newsrc_ent, entries, struct NewsrcEntry);
347 }
348 mdata->newsrc_ent[mdata->newsrc_len].first = first;
349 mdata->newsrc_ent[mdata->newsrc_len].last = last - 1;
350 mdata->newsrc_len++;
351 series = false;
352 }
353 }
354 else
355 {
356 /* search for first read */
357 if (e->deleted || e->read)
358 {
359 first = last + 1;
360 series = true;
361 }
362 last = nntp_edata_get(e)->article_num;
363 }
364 }
365
366 if (series && (first <= mdata->last_loaded))
367 {
368 if (mdata->newsrc_len >= entries)
369 {
370 entries++;
371 MUTT_MEM_REALLOC(&mdata->newsrc_ent, entries, struct NewsrcEntry);
372 }
373 mdata->newsrc_ent[mdata->newsrc_len].first = first;
374 mdata->newsrc_ent[mdata->newsrc_len].last = mdata->last_loaded;
375 mdata->newsrc_len++;
376 }
377 MUTT_MEM_REALLOC(&mdata->newsrc_ent, mdata->newsrc_len, struct NewsrcEntry);
378
379 if (c_sort != EMAIL_SORT_UNSORTED)
380 {
381 cs_subset_str_native_set(NeoMutt->sub, "sort", c_sort, NULL);
383 }
384}
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:233
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition: mailbox.h:190
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:88
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
anum_t article_num
NNTP article number.
Definition: edata.h:36
anum_t last_loaded
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:297
+ 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 393 of file newsrc.c.

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

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

525{
526 char file[PATH_MAX] = { 0 };
527
528 /* server subdirectory */
529 struct Url url = { 0 };
530 account_to_url(cac, &url);
531 url.path = mutt_str_dup(src);
532 url_tostring(&url, file, sizeof(file), U_PATH);
533 FREE(&url.path);
534
535 /* remove trailing slash */
536 char *c = file + strlen(file) - 1;
537 if (*c == '/')
538 *c = '\0';
539
540 struct Buffer *tmp = buf_pool_get();
541 buf_addstr(tmp, file);
542 mutt_encode_path(tmp, file);
543
544 const char *const c_news_cache_dir = cs_subset_path(NeoMutt->sub, "news_cache_dir");
545 snprintf(dst, dstlen, "%s/%s", c_news_cache_dir, buf_string(tmp));
546
547 buf_pool_release(&tmp);
548}
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:226
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:253
void account_to_url(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
Definition: mutt_account.c:80
void mutt_encode_path(struct Buffer *buf, const char *src)
Convert a path to 'us-ascii'.
Definition: muttlib.c:872
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
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:423
#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 556 of file newsrc.c.

557{
558 struct Url url = { 0 };
559
560 account_to_url(cac, &url);
561 url.path = mutt_str_dup(buf);
562 url_tostring(&url, buf, buflen, U_NO_FLAGS);
563 FREE(&url.path);
564}
#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 572 of file newsrc.c.

573{
574 struct NntpAccountData *adata = data;
575 struct NntpMboxData *mdata = NULL;
576 char group[1024] = { 0 };
577 char desc[8192] = { 0 };
578 char mod = '\0';
579 anum_t first = 0, last = 0;
580
581 if (!adata || !line)
582 return 0;
583
584 /* These sscanf limits must match the sizes of the group and desc arrays */
585 if (sscanf(line, "%1023s " ANUM_FMT " " ANUM_FMT " %c %8191[^\n]", group,
586 &last, &first, &mod, desc) < 4)
587 {
588 mutt_debug(LL_DEBUG2, "Can't parse server line: %s\n", line);
589 return 0;
590 }
591
593 mdata->deleted = false;
594 mdata->first_message = first;
595 mdata->last_message = last;
596 mdata->allowed = (mod == 'y') || (mod == 'm');
597 mutt_str_replace(&mdata->desc, desc);
598 if (mdata->newsrc_ent || (mdata->last_cached != 0))
600 else if (mdata->last_message && (mdata->first_message <= mdata->last_message))
601 mdata->unread = mdata->last_message - mdata->first_message + 1;
602 else
603 mdata->unread = 0;
604 return 0;
605}
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:280
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 613 of file newsrc.c.

614{
615 char buf[8192] = { 0 };
616 char file[4096] = { 0 };
617 time_t t = 0;
618
619 cache_expand(file, sizeof(file), &adata->conn->account, ".active");
620 mutt_debug(LL_DEBUG1, "Parsing %s\n", file);
621 FILE *fp = mutt_file_fopen(file, "r");
622 if (!fp)
623 return -1;
624
625 if (!fgets(buf, sizeof(buf), fp) || (sscanf(buf, "%jd%4095s", &t, file) != 1) || (t == 0))
626 {
627 mutt_file_fclose(&fp);
628 return -1;
629 }
630 adata->newgroups_time = t;
631
632 mutt_message(_("Loading list of groups from cache..."));
633 while (fgets(buf, sizeof(buf), fp))
634 nntp_add_group(buf, adata);
635 nntp_add_group(NULL, NULL);
636 mutt_file_fclose(&fp);
638 return 0;
639}
#define mutt_message(...)
Definition: logging2.h:91
#define _(a)
Definition: message.h:28
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
int nntp_add_group(char *line, void *data)
Parse newsgroup.
Definition: newsrc.c:572
static void cache_expand(char *dst, size_t dstlen, struct ConnAccount *cac, const char *src)
Make fully qualified cache file name.
Definition: newsrc.c:524
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:49
time_t newgroups_time
Definition: adata.h:56
struct Connection * conn
Connection to NNTP Server.
Definition: adata.h:62
+ 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 647 of file newsrc.c.

648{
649 if (!adata->cacheable)
650 return 0;
651
652 size_t buflen = 10240;
653 char *buf = MUTT_MEM_CALLOC(buflen, char);
654 snprintf(buf, buflen, "%lu\n", (unsigned long) adata->newgroups_time);
655 size_t off = strlen(buf);
656
657 for (unsigned int i = 0; i < adata->groups_num; i++)
658 {
659 struct NntpMboxData *mdata = adata->groups_list[i];
660
661 if (!mdata || mdata->deleted)
662 continue;
663
664 if ((off + strlen(mdata->group) + (mdata->desc ? strlen(mdata->desc) : 0) + 50) > buflen)
665 {
666 buflen *= 2;
667 MUTT_MEM_REALLOC(&buf, buflen, char);
668 }
669 snprintf(buf + off, buflen - off, "%s " ANUM_FMT " " ANUM_FMT " %c%s%s\n",
670 mdata->group, mdata->last_message, mdata->first_message,
671 mdata->allowed ? 'y' : 'n', mdata->desc ? " " : "",
672 mdata->desc ? mdata->desc : "");
673 off += strlen(buf + off);
674 }
675
676 char file[PATH_MAX] = { 0 };
677 cache_expand(file, sizeof(file), &adata->conn->account, ".active");
678 mutt_debug(LL_DEBUG1, "Updating %s\n", file);
679 int rc = update_file(file, buf);
680 FREE(&buf);
681 return rc;
682}
bool cacheable
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 707 of file newsrc.c.

708{
709 struct Url url = { 0 };
710 char file[PATH_MAX] = { 0 };
711
712 const bool c_save_unsubscribed = cs_subset_bool(NeoMutt->sub, "save_unsubscribed");
713 if (!mdata->adata || !mdata->adata->cacheable || !mdata->adata->conn || !mdata->group ||
714 !(mdata->newsrc_ent || mdata->subscribed || c_save_unsubscribed))
715 {
716 return NULL;
717 }
718
719 account_to_url(&mdata->adata->conn->account, &url);
720 url.path = mdata->group;
721 url_tostring(&url, file, sizeof(file), U_PATH);
722 const char *const c_news_cache_dir = cs_subset_path(NeoMutt->sub, "news_cache_dir");
723 return hcache_open(c_news_cache_dir, file, nntp_hcache_namer, true);
724}
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 char *path, struct Buffer *dest)
Compose hcache file names - Implements hcache_namer_t -.
Definition: newsrc.c:688
struct HeaderCache * hcache_open(const char *path, const char *folder, hcache_namer_t namer, bool create)
Multiplexor for StoreOps::open.
Definition: hcache.c:471
bool subscribed
Definition: mdata.h:42
+ 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 731 of file newsrc.c.

732{
733 if (!hc)
734 return;
735
736 char buf[32] = { 0 };
737 bool old = false;
738 anum_t first = 0, last = 0;
739
740 /* fetch previous values of first and last */
741 char *hdata = hcache_fetch_raw_str(hc, "index", 5);
742 if (hdata)
743 {
744 mutt_debug(LL_DEBUG2, "hcache_fetch_email index: %s\n", hdata);
745 if (sscanf(hdata, ANUM_FMT " " ANUM_FMT, &first, &last) == 2)
746 {
747 old = true;
748 mdata->last_cached = last;
749
750 /* clean removed headers from cache */
751 for (anum_t current = first; current <= last; current++)
752 {
753 if ((current >= mdata->first_message) && (current <= mdata->last_message))
754 continue;
755
756 snprintf(buf, sizeof(buf), ANUM_FMT, current);
757 mutt_debug(LL_DEBUG2, "hcache_delete_email %s\n", buf);
758 hcache_delete_email(hc, buf, strlen(buf));
759 }
760 }
761 FREE(&hdata);
762 }
763
764 /* store current values of first and last */
765 if (!old || (mdata->first_message != first) || (mdata->last_message != last))
766 {
767 snprintf(buf, sizeof(buf), ANUM_FMT " " ANUM_FMT, mdata->first_message,
768 mdata->last_message);
769 mutt_debug(LL_DEBUG2, "hcache_store_email index: %s\n", buf);
770 hcache_store_raw(hc, "index", 5, buf, strlen(buf) + 1);
771 }
772}
int hcache_delete_email(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:739
char * hcache_fetch_raw_str(struct HeaderCache *hc, const char *key, size_t keylen)
Fetch a string from the cache.
Definition: hcache.c:652
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:724
anum_t last_cached
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 799 of file newsrc.c.

800{
802}
int mutt_bcache_list(struct BodyCache *bcache, bcache_list_t want_id, void *data)
Find matching entries in the Body Cache.
Definition: bcache.c:334
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:779
struct BodyCache * bcache
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 808 of file newsrc.c.

809{
810 if (!mdata || !mdata->adata || !mdata->adata->cacheable)
811 return;
812
813#ifdef USE_HCACHE
814 struct Buffer *file = buf_pool_get();
815 nntp_hcache_namer(mdata->group, file);
816 cache_expand(file->data, file->dsize, &mdata->adata->conn->account, buf_string(file));
817 unlink(buf_string(file));
818 mdata->last_cached = 0;
819 mutt_debug(LL_DEBUG2, "%s\n", buf_string(file));
820 buf_pool_release(&file);
821#endif
822
823 if (!mdata->bcache)
824 {
825 mdata->bcache = mutt_bcache_open(&mdata->adata->conn->account, mdata->group);
826 }
827 if (mdata->bcache)
828 {
829 mutt_debug(LL_DEBUG2, "%s/*\n", mdata->group);
831 mutt_bcache_close(&mdata->bcache);
832 }
833}
struct BodyCache * mutt_bcache_open(struct ConnAccount *account, const char *mailbox)
Open an Email-Body Cache.
Definition: bcache.c:146
void mutt_bcache_close(struct BodyCache **ptr)
Close an Email-Body Cache.
Definition: bcache.c:167
size_t dsize
Length of data.
Definition: buffer.h:39
char * data
Pointer to data.
Definition: buffer.h:37
+ 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 841 of file newsrc.c.

842{
843 if (!adata || !adata->cacheable)
844 return;
845
846 struct dirent *de = NULL;
847 DIR *dir = NULL;
848 struct Buffer *cache = buf_pool_get();
849 struct Buffer *file = buf_pool_get();
850
851 cache_expand(cache->data, cache->dsize, &adata->conn->account, NULL);
853 if (!dir)
854 goto done;
855
856 buf_addch(cache, '/');
857 const bool c_save_unsubscribed = cs_subset_bool(NeoMutt->sub, "save_unsubscribed");
858
859 while ((de = readdir(dir)))
860 {
861 char *group = de->d_name;
862 if (mutt_str_equal(group, ".") || mutt_str_equal(group, ".."))
863 continue;
864
865 buf_printf(file, "%s%s", buf_string(cache), group);
866 struct stat st = { 0 };
867 if (stat(buf_string(file), &st) != 0)
868 continue;
869
870#ifdef USE_HCACHE
871 if (S_ISREG(st.st_mode))
872 {
873 char *ext = group + strlen(group) - 7;
874 if ((strlen(group) < 8) || !mutt_str_equal(ext, ".hcache"))
875 continue;
876 *ext = '\0';
877 }
878 else
879#endif
880 if (!S_ISDIR(st.st_mode))
881 continue;
882
883 struct NntpMboxData tmp_mdata = { 0 };
885 if (!mdata)
886 {
887 mdata = &tmp_mdata;
888 mdata->adata = adata;
889 mdata->group = group;
890 mdata->bcache = NULL;
891 }
892 else if (mdata->newsrc_ent || mdata->subscribed || c_save_unsubscribed)
893 {
894 continue;
895 }
896
898 if (S_ISDIR(st.st_mode))
899 {
900 rmdir(buf_string(file));
901 mutt_debug(LL_DEBUG2, "%s\n", buf_string(file));
902 }
903 }
904 closedir(dir);
905
906done:
907 buf_pool_release(&cache);
908 buf_pool_release(&file);
909}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:241
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:642
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition: file.h:63
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
void nntp_delete_group_cache(struct NntpMboxData *mdata)
Remove hcache and bcache of newsgroup.
Definition: newsrc.c:808
+ 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 945 of file newsrc.c.

946{
947 char file[PATH_MAX] = { 0 };
948 int rc;
949 struct ConnAccount cac = { { 0 } };
950 struct NntpAccountData *adata = NULL;
951 struct Connection *conn = NULL;
952
953 if (!server || (*server == '\0'))
954 {
955 mutt_error(_("No news server defined"));
956 return NULL;
957 }
958
959 /* create account from news server url */
960 cac.flags = 0;
961 cac.port = NNTP_PORT;
963 cac.service = "nntp";
965
966 snprintf(file, sizeof(file), "%s%s", strstr(server, "://") ? "" : "news://", server);
967 struct Url *url = url_parse(file);
968 if (!url || (url->path && *url->path) ||
969 !((url->scheme == U_NNTP) || (url->scheme == U_NNTPS)) || !url->host ||
970 (account_from_url(&cac, url) < 0))
971 {
972 url_free(&url);
973 mutt_error(_("%s is an invalid news server specification"), server);
974 return NULL;
975 }
976 if (url->scheme == U_NNTPS)
977 {
978 cac.flags |= MUTT_ACCT_SSL;
979 cac.port = NNTP_SSL_PORT;
980 }
981 url_free(&url);
982
983 // If nntp_user and nntp_pass are specified in the config, use them to find the connection
984 const char *user = NULL;
985 const char *pass = NULL;
986 if ((user = cac.get_field(MUTT_CA_USER, NULL)))
987 {
988 mutt_str_copy(cac.user, user, sizeof(cac.user));
989 cac.flags |= MUTT_ACCT_USER;
990 }
991 if ((pass = cac.get_field(MUTT_CA_PASS, NULL)))
992 {
993 mutt_str_copy(cac.pass, pass, sizeof(cac.pass));
994 cac.flags |= MUTT_ACCT_PASS;
995 }
996
997 /* find connection by account */
998 conn = mutt_conn_find(&cac);
999 if (!conn)
1000 return NULL;
1001 if (!(conn->account.flags & MUTT_ACCT_USER) && cac.flags & MUTT_ACCT_USER)
1002 {
1003 conn->account.flags |= MUTT_ACCT_USER;
1004 conn->account.user[0] = '\0';
1005 }
1006
1007 /* new news server */
1008 adata = nntp_adata_new(conn);
1009
1010 rc = nntp_open_connection(adata);
1011
1012 /* try to create cache directory and enable caching */
1013 adata->cacheable = false;
1014 const char *const c_news_cache_dir = cs_subset_path(NeoMutt->sub, "news_cache_dir");
1015 if ((rc >= 0) && c_news_cache_dir)
1016 {
1017 cache_expand(file, sizeof(file), &conn->account, NULL);
1018 if (mutt_file_mkdir(file, S_IRWXU) < 0)
1019 {
1020 mutt_error(_("Can't create %s: %s"), file, strerror(errno));
1021 }
1022 adata->cacheable = true;
1023 }
1024
1025 /* load .newsrc */
1026 if (rc >= 0)
1027 {
1028 const struct Expando *c_newsrc = cs_subset_expando(NeoMutt->sub, "newsrc");
1029 struct Buffer *buf = buf_pool_get();
1031 buf->dsize, buf);
1032 buf_expand_path(buf);
1033 adata->newsrc_file = buf_strdup(buf);
1034 buf_pool_release(&buf);
1035 rc = nntp_newsrc_parse(adata);
1036 }
1037 if (rc >= 0)
1038 {
1039 /* try to load list of newsgroups from cache */
1040 if (adata->cacheable && (active_get_cache(adata) == 0))
1041 {
1042 rc = nntp_check_new_groups(m, adata);
1043 }
1044 else
1045 {
1046 /* load list of newsgroups from server */
1047 rc = nntp_active_fetch(adata, false);
1048 }
1049 }
1050
1051 if (rc >= 0)
1052 nntp_clear_cache(adata);
1053
1054#ifdef USE_HCACHE
1055 /* check cache files */
1056 if ((rc >= 0) && adata->cacheable)
1057 {
1058 struct dirent *de = NULL;
1059 DIR *dir = mutt_file_opendir(file, MUTT_OPENDIR_NONE);
1060
1061 if (dir)
1062 {
1063 while ((de = readdir(dir)))
1064 {
1065 struct HeaderCache *hc = NULL;
1066 char *group = de->d_name;
1067
1068 char *p = group + strlen(group) - 7;
1069 if ((strlen(group) < 8) || !mutt_str_equal(p, ".hcache"))
1070 continue;
1071 *p = '\0';
1073 if (!mdata)
1074 continue;
1075
1076 hc = nntp_hcache_open(mdata);
1077 if (!hc)
1078 continue;
1079
1080 /* fetch previous values of first and last */
1081 char *hdata = hcache_fetch_raw_str(hc, "index", 5);
1082 if (hdata)
1083 {
1084 anum_t first = 0, last = 0;
1085
1086 if (sscanf(hdata, ANUM_FMT " " ANUM_FMT, &first, &last) == 2)
1087 {
1088 if (mdata->deleted)
1089 {
1090 mdata->first_message = first;
1091 mdata->last_message = last;
1092 }
1093 if ((last >= mdata->first_message) && (last <= mdata->last_message))
1094 {
1095 mdata->last_cached = last;
1096 mutt_debug(LL_DEBUG2, "%s last_cached=" ANUM_FMT "\n", mdata->group, last);
1097 }
1098 }
1099 FREE(&hdata);
1100 }
1101 hcache_close(&hc);
1102 }
1103 closedir(dir);
1104 }
1105 }
1106#endif
1107
1108 if ((rc < 0) || !leave_lock)
1110
1111 if (rc < 0)
1112 {
1117 FREE(&adata);
1118 mutt_socket_close(conn);
1119 FREE(&conn);
1120 return NULL;
1121 }
1122
1123 return adata;
1124}
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:571
const struct Expando * cs_subset_expando(const struct ConfigSubset *sub, const char *name)
Get an Expando config item by name.
Definition: config_type.c:357
@ MUTT_CA_USER
User name.
Definition: connaccount.h:36
@ MUTT_CA_PASS
Password.
Definition: connaccount.h:37
#define MUTT_ACCT_SSL
Account uses SSL/TLS.
Definition: connaccount.h:47
#define MUTT_ACCT_PASS
Password field has been set.
Definition: connaccount.h:46
#define MUTT_ACCT_USER
User field has been set.
Definition: connaccount.h:44
int expando_filter(const struct Expando *exp, const struct ExpandoRenderCallback *erc, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
Render an Expando and run the result through a filter.
Definition: filter.c:138
const struct ExpandoRenderCallback NntpRenderCallbacks[]
Callbacks for Newsrc Expandos.
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:974
static const char * nntp_get_field(enum ConnAccountField field, void *gf_data)
Get connection login credentials - Implements ConnAccount::get_field() -.
Definition: newsrc.c:914
#define mutt_error(...)
Definition: logging2.h:92
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:457
void hcache_close(struct HeaderCache **ptr)
Multiplexor for StoreOps::close.
Definition: hcache.c:542
int account_from_url(struct ConnAccount *cac, const struct Url *url)
Fill ConnAccount with information from url.
Definition: mutt_account.c:44
@ MUTT_ACCT_TYPE_NNTP
Nntp (Usenet) Account.
Definition: mutt_account.h:39
struct Connection * mutt_conn_find(const struct ConnAccount *cac)
Find a connection from a list.
Definition: mutt_socket.c:89
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:315
struct HeaderCache * nntp_hcache_open(struct NntpMboxData *mdata)
Open newsgroup hcache.
Definition: newsrc.c:707
void nntp_clear_cache(struct NntpAccountData *adata)
Clear the NNTP cache.
Definition: newsrc.c:841
int nntp_newsrc_parse(struct NntpAccountData *adata)
Parse .newsrc file.
Definition: newsrc.c:164
static int active_get_cache(struct NntpAccountData *adata)
Load list of all newsgroups from cache.
Definition: newsrc.c:613
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:2037
#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:2105
int nntp_open_connection(struct NntpAccountData *adata)
Connect to server, authenticate and get capabilities.
Definition: nntp.c:1766
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: render.h:33
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition: socket.c:100
Login details for a remote server.
Definition: connaccount.h:53
char user[128]
Username.
Definition: connaccount.h:56
char pass[256]
Password.
Definition: connaccount.h:57
const char * service
Name of the service, e.g. "imap".
Definition: connaccount.h:61
const char *(* get_field)(enum ConnAccountField field, void *gf_data)
Definition: connaccount.h:70
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
Parsed Expando trees.
Definition: expando.h:41
Header Cache.
Definition: lib.h:86
char * authenticators
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:239
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 1138 of file newsrc.c.

1139{
1140 struct NntpMboxData *mdata = m->mdata;
1141
1142 if (group)
1143 mdata = mutt_hash_find(mdata->adata->groups_hash, group);
1144
1145 if (!mdata)
1146 return;
1147
1148 for (unsigned int i = 0; i < mdata->newsrc_len; i++)
1149 {
1150 if ((anum >= mdata->newsrc_ent[i].first) && (anum <= mdata->newsrc_ent[i].last))
1151 {
1152 /* can't use mutt_set_flag() because mview_update() didn't get called yet */
1153 e->read = true;
1154 return;
1155 }
1156 }
1157
1158 /* article was not cached yet, it's new */
1159 if (anum > mdata->last_cached)
1160 return;
1161
1162 /* article isn't read but cached, it's old */
1163 const bool c_mark_old = cs_subset_bool(NeoMutt->sub, "mark_old");
1164 if (c_mark_old)
1165 e->old = true;
1166}
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 1175 of file newsrc.c.

1176{
1177 if (!adata || !adata->groups_hash || !group || (*group == '\0'))
1178 return NULL;
1179
1181 mdata->subscribed = true;
1182 if (!mdata->newsrc_ent)
1183 {
1184 mdata->newsrc_ent = MUTT_MEM_CALLOC(1, struct NewsrcEntry);
1185 mdata->newsrc_len = 1;
1186 mdata->newsrc_ent[0].first = 1;
1187 mdata->newsrc_ent[0].last = 0;
1188 }
1189 return mdata;
1190}
+ 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 1199 of file newsrc.c.

1200{
1201 if (!adata || !adata->groups_hash || !group || (*group == '\0'))
1202 return NULL;
1203
1205 if (!mdata)
1206 return NULL;
1207
1208 mdata->subscribed = false;
1209 const bool c_save_unsubscribed = cs_subset_bool(NeoMutt->sub, "save_unsubscribed");
1210 if (!c_save_unsubscribed)
1211 {
1212 mdata->newsrc_len = 0;
1213 FREE(&mdata->newsrc_ent);
1214 }
1215 return mdata;
1216}
+ 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 1226 of file newsrc.c.

1228{
1229 if (!adata || !adata->groups_hash || !group || (*group == '\0'))
1230 return NULL;
1231
1233 if (!mdata)
1234 return NULL;
1235
1236 if (mdata->newsrc_ent)
1237 {
1238 MUTT_MEM_REALLOC(&mdata->newsrc_ent, 1, struct NewsrcEntry);
1239 mdata->newsrc_len = 1;
1240 mdata->newsrc_ent[0].first = 1;
1241 mdata->newsrc_ent[0].last = mdata->last_message;
1242 }
1243 mdata->unread = 0;
1244 if (m && (m->mdata == mdata))
1245 {
1246 for (unsigned int i = 0; i < m->msg_count; i++)
1247 {
1248 struct Email *e = m->emails[i];
1249 if (!e)
1250 break;
1251 mutt_set_flag(m, e, MUTT_READ, true, true);
1252 }
1253 }
1254 return mdata;
1255}
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:57
@ MUTT_READ
Messages that have been read.
Definition: mutt.h:73
+ 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 1265 of file newsrc.c.

1267{
1268 if (!adata || !adata->groups_hash || !group || (*group == '\0'))
1269 return NULL;
1270
1272 if (!mdata)
1273 return NULL;
1274
1275 if (mdata->newsrc_ent)
1276 {
1277 MUTT_MEM_REALLOC(&mdata->newsrc_ent, 1, struct NewsrcEntry);
1278 mdata->newsrc_len = 1;
1279 mdata->newsrc_ent[0].first = 1;
1280 mdata->newsrc_ent[0].last = mdata->first_message - 1;
1281 }
1282 if (m && (m->mdata == mdata))
1283 {
1284 mdata->unread = m->msg_count;
1285 for (unsigned int i = 0; i < m->msg_count; i++)
1286 {
1287 struct Email *e = m->emails[i];
1288 if (!e)
1289 break;
1290 mutt_set_flag(m, e, MUTT_READ, false, true);
1291 }
1292 }
1293 else
1294 {
1295 mdata->unread = mdata->last_message;
1296 if (mdata->newsrc_ent)
1297 mdata->unread -= mdata->newsrc_ent[0].last;
1298 }
1299 return mdata;
1300}
+ 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 1308 of file newsrc.c.

1309{
1310 if (!m)
1311 return;
1312
1313 for (unsigned int i = 0; i < CurrentNewsSrv->groups_num; i++)
1314 {
1316
1317 if (!mdata || !mdata->subscribed || !mdata->unread)
1318 continue;
1319
1320 if ((m->type == MUTT_NNTP) &&
1321 mutt_str_equal(mdata->group, ((struct NntpMboxData *) m->mdata)->group))
1322 {
1323 unsigned int unread = 0;
1324
1325 for (unsigned int j = 0; j < m->msg_count; j++)
1326 {
1327 struct Email *e = m->emails[j];
1328 if (!e)
1329 break;
1330 if (!e->read && !e->deleted)
1331 unread++;
1332 }
1333 if (unread == 0)
1334 continue;
1335 }
1336 mutt_str_copy(buf, mdata->group, buflen);
1337 break;
1338 }
1339}
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition: mailbox.h:49
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:77
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
+ Here is the call graph for this function:
+ Here is the caller graph for this function: