NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
nntp.c File Reference

Usenet network mailbox type; talk to an NNTP server. More...

#include "config.h"
#include <ctype.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <strings.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 "lib.h"
#include "bcache/lib.h"
#include "hcache/lib.h"
#include "ncrypt/lib.h"
#include "progress/lib.h"
#include "question/lib.h"
#include "adata.h"
#include "attachments.h"
#include "edata.h"
#include "hook.h"
#include "mdata.h"
#include "mutt_logging.h"
#include "mutt_socket.h"
#include "muttlib.h"
#include "mx.h"
#include "protos.h"
#include <sasl/sasl.h>
#include <sasl/saslutil.h>
#include "mutt.h"
+ Include dependency graph for nntp.c:

Go to the source code of this file.

Data Structures

struct  FetchCtx
 Keep track when getting data from a server. More...
 
struct  ChildCtx
 Keep track of the children of an article. More...
 

Functions

void nntp_hashelem_free (int type, void *obj, intptr_t data)
 Free our hash table data - Implements hash_hdata_free_t. More...
 
static int nntp_connect_error (struct NntpAccountData *adata)
 Signal a failed connection. More...
 
static int nntp_capabilities (struct NntpAccountData *adata)
 Get capabilities. More...
 
static int nntp_attempt_features (struct NntpAccountData *adata)
 Detect supported commands. More...
 
static bool nntp_memchr (char **haystack, char *sentinel, int needle)
 look for a char in a binary buf, conveniently More...
 
static void nntp_log_binbuf (const char *buf, size_t len, const char *pfx, int dbg)
 log a buffer possibly containing NUL bytes More...
 
static int nntp_auth (struct NntpAccountData *adata)
 Get login, password and authenticate. More...
 
static int nntp_query (struct NntpMboxData *mdata, char *line, size_t linelen)
 Send data from buffer and receive answer to same buffer. More...
 
static int nntp_fetch_lines (struct NntpMboxData *mdata, char *query, size_t qlen, const char *msg, int(*func)(char *, void *), void *data)
 Read lines, calling a callback function for each. More...
 
static int fetch_description (char *line, void *data)
 Parse newsgroup description. More...
 
static int get_description (struct NntpMboxData *mdata, const char *wildmat, const char *msg)
 Fetch newsgroups descriptions. More...
 
static void nntp_parse_xref (struct Mailbox *m, struct Email *e)
 Parse cross-reference. More...
 
static int fetch_tempfile (char *line, void *data)
 Write line to temporary file. More...
 
static int fetch_numbers (char *line, void *data)
 Parse article number. More...
 
static int parse_overview_line (char *line, void *data)
 Parse overview line. More...
 
static int nntp_fetch_headers (struct Mailbox *m, void *hc, anum_t first, anum_t last, bool restore)
 Fetch headers. More...
 
static int nntp_group_poll (struct NntpMboxData *mdata, bool update_stat)
 Check newsgroup for new articles. More...
 
static enum MxStatus check_mailbox (struct Mailbox *m)
 Check current newsgroup for new articles. More...
 
static int nntp_date (struct NntpAccountData *adata, time_t *now)
 Get date and time from server. More...
 
static int fetch_children (char *line, void *data)
 Parse XPAT line. More...
 
int nntp_open_connection (struct NntpAccountData *adata)
 Connect to server, authenticate and get capabilities. More...
 
int nntp_post (struct Mailbox *m, const char *msg)
 Post article. More...
 
int nntp_active_fetch (struct NntpAccountData *adata, bool mark_new)
 Fetch list of all newsgroups from server. More...
 
int nntp_check_new_groups (struct Mailbox *m, struct NntpAccountData *adata)
 Check for new groups/articles in subscribed groups. More...
 
int nntp_check_msgid (struct Mailbox *m, const char *msgid)
 Fetch article by Message-ID. More...
 
int nntp_check_children (struct Mailbox *m, const char *msgid)
 Fetch children of article with the Message-ID. More...
 
int nntp_compare_order (const struct Email *a, const struct Email *b, bool reverse)
 Sort to mailbox order - Implements sort_mail_t. More...
 
static bool nntp_ac_owns_path (struct Account *a, const char *path)
 Check whether an Account owns a Mailbox path - Implements MxOps::ac_owns_path() -. More...
 
static bool nntp_ac_add (struct Account *a, struct Mailbox *m)
 Add a Mailbox to an Account - Implements MxOps::ac_add() -. More...
 
static enum MxOpenReturns nntp_mbox_open (struct Mailbox *m)
 Open a Mailbox - Implements MxOps::mbox_open() -. More...
 
static enum MxStatus nntp_mbox_check (struct Mailbox *m)
 Check for new mail - Implements MxOps::mbox_check() -. More...
 
static enum MxStatus nntp_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -. More...
 
static enum MxStatus nntp_mbox_close (struct Mailbox *m)
 Close a Mailbox - Implements MxOps::mbox_close() -. More...
 
static bool nntp_msg_open (struct Mailbox *m, struct Message *msg, int msgno)
 Open an email message in a Mailbox - Implements MxOps::msg_open() -. More...
 
static int nntp_msg_close (struct Mailbox *m, struct Message *msg)
 Close an email - Implements MxOps::msg_close() -. More...
 
enum MailboxType nntp_path_probe (const char *path, const struct stat *st)
 Is this an NNTP Mailbox? - Implements MxOps::path_probe() -. More...
 
static int nntp_path_canon (char *buf, size_t buflen)
 Canonicalise a Mailbox path - Implements MxOps::path_canon() -. More...
 
static int nntp_path_pretty (char *buf, size_t buflen, const char *folder)
 Abbreviate a Mailbox path - Implements MxOps::path_pretty() -. More...
 
static int nntp_path_parent (char *buf, size_t buflen)
 Find the parent of a Mailbox path - Implements MxOps::path_parent() -. More...
 

Variables

struct NntpAccountDataCurrentNewsSrv
 Current NNTP news server. More...
 
const char * OverviewFmt
 
struct MxOps MxNntpOps
 NNTP Mailbox - Implements MxOps -. More...
 

Detailed Description

Usenet network mailbox type; talk to an NNTP server.

Authors
  • Brandon Long
  • Andrej Gritsenko
  • Vsevolod Volkov
  • Richard Russon

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 nntp.c.

Function Documentation

◆ nntp_hashelem_free()

void nntp_hashelem_free ( int  type,
void *  obj,
intptr_t  data 
)

Free our hash table data - Implements hash_hdata_free_t.

Definition at line 117 of file nntp.c.

118 {
119  nntp_mdata_free(&obj);
120 }
void nntp_mdata_free(void **ptr)
Free the private Mailbox data - Implements Mailbox::mdata_free()
Definition: mdata.c:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_connect_error()

static int nntp_connect_error ( struct NntpAccountData adata)
static

Signal a failed connection.

Parameters
adataNNTP server
Return values
-1Always

Definition at line 127 of file nntp.c.

128 {
129  adata->status = NNTP_NONE;
130  mutt_error(_("Server closed connection"));
131  return -1;
132 }
#define mutt_error(...)
Definition: logging.h:88
#define _(a)
Definition: message.h:28
unsigned int status
Definition: adata.h:48
No connection to server.
Definition: private.h:44
+ Here is the caller graph for this function:

◆ nntp_capabilities()

static int nntp_capabilities ( struct NntpAccountData adata)
static

Get capabilities.

Parameters
adataNNTP server
Return values
-1Error, connection is closed
0Mode is reader, capabilities set up
1Need to switch to reader mode

Definition at line 141 of file nntp.c.

142 {
143  struct Connection *conn = adata->conn;
144  bool mode_reader = false;
145  char buf[1024];
146  char authinfo[1024] = { 0 };
147 
148  adata->hasCAPABILITIES = false;
149  adata->hasSTARTTLS = false;
150  adata->hasDATE = false;
151  adata->hasLIST_NEWSGROUPS = false;
152  adata->hasLISTGROUP = false;
153  adata->hasLISTGROUPrange = false;
154  adata->hasOVER = false;
155  FREE(&adata->authenticators);
156 
157  if ((mutt_socket_send(conn, "CAPABILITIES\r\n") < 0) ||
158  (mutt_socket_readln(buf, sizeof(buf), conn) < 0))
159  {
160  return nntp_connect_error(adata);
161  }
162 
163  /* no capabilities */
164  if (!mutt_str_startswith(buf, "101"))
165  return 1;
166  adata->hasCAPABILITIES = true;
167 
168  /* parse capabilities */
169  do
170  {
171  size_t plen = 0;
172  if (mutt_socket_readln(buf, sizeof(buf), conn) < 0)
173  return nntp_connect_error(adata);
174  if (mutt_str_equal("STARTTLS", buf))
175  adata->hasSTARTTLS = true;
176  else if (mutt_str_equal("MODE-READER", buf))
177  mode_reader = true;
178  else if (mutt_str_equal("READER", buf))
179  {
180  adata->hasDATE = true;
181  adata->hasLISTGROUP = true;
182  adata->hasLISTGROUPrange = true;
183  }
184  else if ((plen = mutt_str_startswith(buf, "AUTHINFO ")))
185  {
186  mutt_str_cat(buf, sizeof(buf), " ");
187  mutt_str_copy(authinfo, buf + plen - 1, sizeof(authinfo));
188  }
189 #ifdef USE_SASL
190  else if ((plen = mutt_str_startswith(buf, "SASL ")))
191  {
192  char *p = buf + plen;
193  while (*p == ' ')
194  p++;
195  adata->authenticators = mutt_str_dup(p);
196  }
197 #endif
198  else if (mutt_str_equal("OVER", buf))
199  adata->hasOVER = true;
200  else if (mutt_str_startswith(buf, "LIST "))
201  {
202  char *p = strstr(buf, " NEWSGROUPS");
203  if (p)
204  {
205  p += 11;
206  if ((*p == '\0') || (*p == ' '))
207  adata->hasLIST_NEWSGROUPS = true;
208  }
209  }
210  } while (!mutt_str_equal(".", buf));
211  *buf = '\0';
212 #ifdef USE_SASL
213  if (adata->authenticators && strcasestr(authinfo, " SASL "))
214  mutt_str_copy(buf, adata->authenticators, sizeof(buf));
215 #endif
216  if (strcasestr(authinfo, " USER "))
217  {
218  if (*buf != '\0')
219  mutt_str_cat(buf, sizeof(buf), " ");
220  mutt_str_cat(buf, sizeof(buf), "USER");
221  }
222  mutt_str_replace(&adata->authenticators, buf);
223 
224  /* current mode is reader */
225  if (adata->hasDATE)
226  return 0;
227 
228  /* server is mode-switching, need to switch to reader mode */
229  if (mode_reader)
230  return 1;
231 
232  mutt_socket_close(conn);
233  adata->status = NNTP_BYE;
234  mutt_error(_("Server doesn't support reader mode"));
235  return -1;
236 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:37
#define mutt_error(...)
Definition: logging.h:88
Disconnected from server.
Definition: private.h:46
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define _(a)
Definition: message.h:28
static int nntp_connect_error(struct NntpAccountData *adata)
Signal a failed connection.
Definition: nntp.c:127
bool hasSTARTTLS
Definition: adata.h:39
bool hasLIST_NEWSGROUPS
Definition: adata.h:41
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
unsigned int status
Definition: adata.h:48
bool hasLISTGROUP
Definition: adata.h:43
bool hasOVER
Definition: adata.h:45
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition: socket.c:97
char * mutt_str_cat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:385
#define mutt_socket_readln(buf, buflen, conn)
Definition: mutt_socket.h:36
struct Connection * conn
Definition: adata.h:63
char * authenticators
Definition: adata.h:53
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:749
bool hasLISTGROUPrange
Definition: adata.h:44
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
#define FREE(x)
Definition: memory.h:40
bool hasDATE
Definition: adata.h:40
bool hasCAPABILITIES
Definition: adata.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_attempt_features()

static int nntp_attempt_features ( struct NntpAccountData adata)
static

Detect supported commands.

Parameters
adataNNTP server
Return values
0Success
-1Failure

Definition at line 244 of file nntp.c.

245 {
246  struct Connection *conn = adata->conn;
247  char buf[1024];
248 
249  /* no CAPABILITIES, trying DATE, LISTGROUP, LIST NEWSGROUPS */
250  if (!adata->hasCAPABILITIES)
251  {
252  if ((mutt_socket_send(conn, "DATE\r\n") < 0) ||
253  (mutt_socket_readln(buf, sizeof(buf), conn) < 0))
254  {
255  return nntp_connect_error(adata);
256  }
257  if (!mutt_str_startswith(buf, "500"))
258  adata->hasDATE = true;
259 
260  if ((mutt_socket_send(conn, "LISTGROUP\r\n") < 0) ||
261  (mutt_socket_readln(buf, sizeof(buf), conn) < 0))
262  {
263  return nntp_connect_error(adata);
264  }
265  if (!mutt_str_startswith(buf, "500"))
266  adata->hasLISTGROUP = true;
267 
268  if ((mutt_socket_send(conn, "LIST NEWSGROUPS +\r\n") < 0) ||
269  (mutt_socket_readln(buf, sizeof(buf), conn) < 0))
270  {
271  return nntp_connect_error(adata);
272  }
273  if (!mutt_str_startswith(buf, "500"))
274  adata->hasLIST_NEWSGROUPS = true;
275  if (mutt_str_startswith(buf, "215"))
276  {
277  do
278  {
279  if (mutt_socket_readln(buf, sizeof(buf), conn) < 0)
280  return nntp_connect_error(adata);
281  } while (!mutt_str_equal(".", buf));
282  }
283  }
284 
285  /* no LIST NEWSGROUPS, trying XGTITLE */
286  if (!adata->hasLIST_NEWSGROUPS)
287  {
288  if ((mutt_socket_send(conn, "XGTITLE\r\n") < 0) ||
289  (mutt_socket_readln(buf, sizeof(buf), conn) < 0))
290  {
291  return nntp_connect_error(adata);
292  }
293  if (!mutt_str_startswith(buf, "500"))
294  adata->hasXGTITLE = true;
295  }
296 
297  /* no OVER, trying XOVER */
298  if (!adata->hasOVER)
299  {
300  if ((mutt_socket_send(conn, "XOVER\r\n") < 0) ||
301  (mutt_socket_readln(buf, sizeof(buf), conn) < 0))
302  {
303  return nntp_connect_error(adata);
304  }
305  if (!mutt_str_startswith(buf, "500"))
306  adata->hasXOVER = true;
307  }
308 
309  /* trying LIST OVERVIEW.FMT */
310  if (adata->hasOVER || adata->hasXOVER)
311  {
312  if ((mutt_socket_send(conn, "LIST OVERVIEW.FMT\r\n") < 0) ||
313  (mutt_socket_readln(buf, sizeof(buf), conn) < 0))
314  {
315  return nntp_connect_error(adata);
316  }
317  if (!mutt_str_startswith(buf, "215"))
319  else
320  {
321  bool cont = false;
322  size_t buflen = 2048, off = 0, b = 0;
323 
324  FREE(&adata->overview_fmt);
325  adata->overview_fmt = mutt_mem_malloc(buflen);
326 
327  while (true)
328  {
329  if ((buflen - off) < 1024)
330  {
331  buflen *= 2;
332  mutt_mem_realloc(&adata->overview_fmt, buflen);
333  }
334 
335  const int chunk = mutt_socket_readln_d(adata->overview_fmt + off,
336  buflen - off, conn, MUTT_SOCK_LOG_HDR);
337  if (chunk < 0)
338  {
339  FREE(&adata->overview_fmt);
340  return nntp_connect_error(adata);
341  }
342 
343  if (!cont && mutt_str_equal(".", adata->overview_fmt + off))
344  break;
345 
346  cont = (chunk >= (buflen - off));
347  off += strlen(adata->overview_fmt + off);
348  if (!cont)
349  {
350  if (adata->overview_fmt[b] == ':')
351  {
352  memmove(adata->overview_fmt + b, adata->overview_fmt + b + 1, off - b - 1);
353  adata->overview_fmt[off - 1] = ':';
354  }
355  char *colon = strchr(adata->overview_fmt + b, ':');
356  if (!colon)
357  adata->overview_fmt[off++] = ':';
358  else if (strcmp(colon + 1, "full") != 0)
359  off = colon + 1 - adata->overview_fmt;
360  if (strcasecmp(adata->overview_fmt + b, "Bytes:") == 0)
361  {
362  size_t len = strlen(adata->overview_fmt + b);
363  mutt_str_copy(adata->overview_fmt + b, "Content-Length:", len + 1);
364  off = b + len;
365  }
366  adata->overview_fmt[off++] = '\0';
367  b = off;
368  }
369  }
370  adata->overview_fmt[off++] = '\0';
371  mutt_mem_realloc(&adata->overview_fmt, off);
372  }
373  }
374  return 0;
375 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:37
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
static int nntp_connect_error(struct NntpAccountData *adata)
Signal a failed connection.
Definition: nntp.c:127
const char * OverviewFmt
Definition: nntp.c:80
bool hasLIST_NEWSGROUPS
Definition: adata.h:41
char * overview_fmt
Definition: adata.h:54
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
bool hasXGTITLE
Definition: adata.h:42
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
bool hasLISTGROUP
Definition: adata.h:43
bool hasOVER
Definition: adata.h:45
#define mutt_socket_readln(buf, buflen, conn)
Definition: mutt_socket.h:36
struct Connection * conn
Definition: adata.h:63
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:749
#define FREE(x)
Definition: memory.h:40
int mutt_socket_readln_d(char *buf, size_t buflen, struct Connection *conn, int dbg)
Read a line from a socket.
Definition: socket.c:246
bool hasXOVER
Definition: adata.h:46
bool hasDATE
Definition: adata.h:40
bool hasCAPABILITIES
Definition: adata.h:38
#define MUTT_SOCK_LOG_HDR
Definition: mutt_socket.h:30
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_memchr()

static bool nntp_memchr ( char **  haystack,
char *  sentinel,
int  needle 
)
static

look for a char in a binary buf, conveniently

Parameters
haystack[in/out] input: start here, output: store address of hit
sentinelpoints just beyond (1 byte after) search area
needlethe character to search for
Return values
truefound and updated haystack
falsenot found

Definition at line 386 of file nntp.c.

387 {
388  char *start = *haystack;
389  size_t max_offset = sentinel - start;
390  void *vp = memchr(start, max_offset, needle);
391  if (!vp)
392  return false;
393  *haystack = vp;
394  return true;
395 }
+ Here is the caller graph for this function:

◆ nntp_log_binbuf()

static void nntp_log_binbuf ( const char *  buf,
size_t  len,
const char *  pfx,
int  dbg 
)
static

log a buffer possibly containing NUL bytes

Parameters
bufsource buffer
lenhow many bytes from buf
pfxlogging prefix (protocol etc.)
dbgwhich loglevel does message belong

Definition at line 404 of file nntp.c.

405 {
406  char tmp[1024];
407  char *p = tmp;
408  char *sentinel = tmp + len;
409 
410  const short c_debug_level = cs_subset_number(NeoMutt->sub, "debug_level");
411  if (c_debug_level < dbg)
412  return;
413  memcpy(tmp, buf, len);
414  tmp[len] = '\0';
415  while (nntp_memchr(&p, sentinel, '\0'))
416  *p = '.';
417  mutt_debug(dbg, "%s> %s\n", pfx, tmp);
418 }
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
Container for Accounts, Notifications.
Definition: neomutt.h:36
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
static bool nntp_memchr(char **haystack, char *sentinel, int needle)
look for a char in a binary buf, conveniently
Definition: nntp.c:386
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_auth()

static int nntp_auth ( struct NntpAccountData adata)
static

Get login, password and authenticate.

Parameters
adataNNTP server
Return values
0Success
-1Failure

Definition at line 427 of file nntp.c.

428 {
429  struct Connection *conn = adata->conn;
430  char buf[1024];
431  char authenticators[1024] = "USER";
432  char *method = NULL, *a = NULL, *p = NULL;
433  unsigned char flags = conn->account.flags;
434 
435  while (true)
436  {
437  /* get login and password */
438  if ((mutt_account_getuser(&conn->account) < 0) || (conn->account.user[0] == '\0') ||
439  (mutt_account_getpass(&conn->account) < 0) || (conn->account.pass[0] == '\0'))
440  {
441  break;
442  }
443 
444  /* get list of authenticators */
445  const char *const c_nntp_authenticators =
446  cs_subset_string(NeoMutt->sub, "nntp_authenticators");
447  if (c_nntp_authenticators)
448  mutt_str_copy(authenticators, c_nntp_authenticators, sizeof(authenticators));
449  else if (adata->hasCAPABILITIES)
450  {
451  mutt_str_copy(authenticators, adata->authenticators, sizeof(authenticators));
452  p = authenticators;
453  while (*p)
454  {
455  if (*p == ' ')
456  *p = ':';
457  p++;
458  }
459  }
460  p = authenticators;
461  while (*p)
462  {
463  *p = toupper(*p);
464  p++;
465  }
466 
467  mutt_debug(LL_DEBUG1, "available methods: %s\n", adata->authenticators);
468  a = authenticators;
469  while (true)
470  {
471  if (!a)
472  {
473  mutt_error(_("No authenticators available"));
474  break;
475  }
476 
477  method = a;
478  a = strchr(a, ':');
479  if (a)
480  *a++ = '\0';
481 
482  /* check authenticator */
483  if (adata->hasCAPABILITIES)
484  {
485  char *m = NULL;
486 
487  if (!adata->authenticators)
488  continue;
489  m = strcasestr(adata->authenticators, method);
490  if (!m)
491  continue;
492  if ((m > adata->authenticators) && (*(m - 1) != ' '))
493  continue;
494  m += strlen(method);
495  if ((*m != '\0') && (*m != ' '))
496  continue;
497  }
498  mutt_debug(LL_DEBUG1, "trying method %s\n", method);
499 
500  /* AUTHINFO USER authentication */
501  if (strcmp(method, "USER") == 0)
502  {
503  // L10N: (%s) is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
504  mutt_message(_("Authenticating (%s)..."), method);
505  snprintf(buf, sizeof(buf), "AUTHINFO USER %s\r\n", conn->account.user);
506  if ((mutt_socket_send(conn, buf) < 0) ||
507  (mutt_socket_readln_d(buf, sizeof(buf), conn, MUTT_SOCK_LOG_FULL) < 0))
508  {
509  break;
510  }
511 
512  /* authenticated, password is not required */
513  if (mutt_str_startswith(buf, "281"))
514  return 0;
515 
516  /* username accepted, sending password */
517  if (mutt_str_startswith(buf, "381"))
518  {
519  mutt_debug(MUTT_SOCK_LOG_FULL, "%d> AUTHINFO PASS *\n", conn->fd);
520  snprintf(buf, sizeof(buf), "AUTHINFO PASS %s\r\n", conn->account.pass);
521  if ((mutt_socket_send_d(conn, buf, MUTT_SOCK_LOG_FULL) < 0) ||
522  (mutt_socket_readln_d(buf, sizeof(buf), conn, MUTT_SOCK_LOG_FULL) < 0))
523  {
524  break;
525  }
526 
527  /* authenticated */
528  if (mutt_str_startswith(buf, "281"))
529  return 0;
530  }
531 
532  /* server doesn't support AUTHINFO USER, trying next method */
533  if (*buf == '5')
534  continue;
535  }
536  else
537  {
538 #ifdef USE_SASL
539  sasl_conn_t *saslconn = NULL;
540  sasl_interact_t *interaction = NULL;
541  int rc;
542  char inbuf[1024] = { 0 };
543  const char *mech = NULL;
544  const char *client_out = NULL;
545  unsigned int client_len, len;
546 
547  if (mutt_sasl_client_new(conn, &saslconn) < 0)
548  {
549  mutt_debug(LL_DEBUG1, "error allocating SASL connection\n");
550  continue;
551  }
552 
553  while (true)
554  {
555  rc = sasl_client_start(saslconn, method, &interaction, &client_out,
556  &client_len, &mech);
557  if (rc != SASL_INTERACT)
558  break;
559  mutt_sasl_interact(interaction);
560  }
561  if ((rc != SASL_OK) && (rc != SASL_CONTINUE))
562  {
563  sasl_dispose(&saslconn);
565  "error starting SASL authentication exchange\n");
566  continue;
567  }
568 
569  // L10N: (%s) is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
570  mutt_message(_("Authenticating (%s)..."), method);
571  snprintf(buf, sizeof(buf), "AUTHINFO SASL %s", method);
572 
573  /* looping protocol */
574  while ((rc == SASL_CONTINUE) || ((rc == SASL_OK) && client_len))
575  {
576  /* send out client response */
577  if (client_len)
578  {
579  nntp_log_binbuf(client_out, client_len, "SASL", MUTT_SOCK_LOG_FULL);
580  if (*buf != '\0')
581  mutt_str_cat(buf, sizeof(buf), " ");
582  len = strlen(buf);
583  if (sasl_encode64(client_out, client_len, buf + len,
584  sizeof(buf) - len, &len) != SASL_OK)
585  {
586  mutt_debug(LL_DEBUG1, "error base64-encoding client response\n");
587  break;
588  }
589  }
590 
591  mutt_str_cat(buf, sizeof(buf), "\r\n");
592  if (strchr(buf, ' '))
593  {
594  mutt_debug(MUTT_SOCK_LOG_CMD, "%d> AUTHINFO SASL %s%s\n", conn->fd,
595  method, client_len ? " sasl_data" : "");
596  }
597  else
598  mutt_debug(MUTT_SOCK_LOG_CMD, "%d> sasl_data\n", conn->fd);
599  client_len = 0;
600  if ((mutt_socket_send_d(conn, buf, MUTT_SOCK_LOG_FULL) < 0) ||
601  (mutt_socket_readln_d(inbuf, sizeof(inbuf), conn, MUTT_SOCK_LOG_FULL) < 0))
602  {
603  break;
604  }
605  if (!mutt_str_startswith(inbuf, "283 ") && !mutt_str_startswith(inbuf, "383 "))
606  {
607  mutt_debug(MUTT_SOCK_LOG_FULL, "%d< %s\n", conn->fd, inbuf);
608  break;
609  }
610  inbuf[3] = '\0';
611  mutt_debug(MUTT_SOCK_LOG_FULL, "%d< %s sasl_data\n", conn->fd, inbuf);
612 
613  if (strcmp("=", inbuf + 4) == 0)
614  len = 0;
615  else if (sasl_decode64(inbuf + 4, strlen(inbuf + 4), buf,
616  sizeof(buf) - 1, &len) != SASL_OK)
617  {
618  mutt_debug(LL_DEBUG1, "error base64-decoding server response\n");
619  break;
620  }
621  else
622  nntp_log_binbuf(buf, len, "SASL", MUTT_SOCK_LOG_FULL);
623 
624  while (true)
625  {
626  rc = sasl_client_step(saslconn, buf, len, &interaction, &client_out, &client_len);
627  if (rc != SASL_INTERACT)
628  break;
629  mutt_sasl_interact(interaction);
630  }
631  if (*inbuf != '3')
632  break;
633 
634  *buf = '\0';
635  } /* looping protocol */
636 
637  if ((rc == SASL_OK) && (client_len == 0) && (*inbuf == '2'))
638  {
639  mutt_sasl_setup_conn(conn, saslconn);
640  return 0;
641  }
642 
643  /* terminate SASL session */
644  sasl_dispose(&saslconn);
645  if (conn->fd < 0)
646  break;
647  if (mutt_str_startswith(inbuf, "383 "))
648  {
649  if ((mutt_socket_send(conn, "*\r\n") < 0) ||
650  (mutt_socket_readln(inbuf, sizeof(inbuf), conn) < 0))
651  {
652  break;
653  }
654  }
655 
656  /* server doesn't support AUTHINFO SASL, trying next method */
657  if (*inbuf == '5')
658  continue;
659 #else
660  continue;
661 #endif /* USE_SASL */
662  }
663 
664  // L10N: %s is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
665  mutt_error(_("%s authentication failed"), method);
666  break;
667  }
668  break;
669  }
670 
671  /* error */
672  adata->status = NNTP_BYE;
673  conn->account.flags = flags;
674  if (conn->fd < 0)
675  {
676  mutt_error(_("Server closed connection"));
677  }
678  else
679  mutt_socket_close(conn);
680  return -1;
681 }
int mutt_account_getuser(struct ConnAccount *cac)
Retrieve username into ConnAccount, if necessary.
Definition: connaccount.c:47
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:40
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:37
#define mutt_error(...)
Definition: logging.h:88
Disconnected from server.
Definition: private.h:46
char user[128]
Username.
Definition: connaccount.h:55
#define _(a)
Definition: message.h:28
int mutt_sasl_client_new(struct Connection *conn, sasl_conn_t **saslconn)
Wrapper for sasl_client_new()
Definition: sasl.c:603
void mutt_sasl_setup_conn(struct Connection *conn, sasl_conn_t *saslconn)
Set up an SASL connection.
Definition: sasl.c:734
static void nntp_log_binbuf(const char *buf, size_t len, const char *pfx, int dbg)
log a buffer possibly containing NUL bytes
Definition: nntp.c:404
#define MUTT_SOCK_LOG_CMD
Definition: mutt_socket.h:29
#define MUTT_SOCK_LOG_FULL
Definition: mutt_socket.h:31
Container for Accounts, Notifications.
Definition: neomutt.h:36
char inbuf[1024]
Buffer for incoming traffic.
Definition: connection.h:42
char pass[256]
Password.
Definition: connaccount.h:56
#define mutt_socket_send_d(conn, buf, dbg)
Definition: mutt_socket.h:38
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
unsigned int status
Definition: adata.h:48
int fd
Socket file descriptor.
Definition: connection.h:44
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition: socket.c:97
char * mutt_str_cat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:385
#define mutt_socket_readln(buf, buflen, conn)
Definition: mutt_socket.h:36
struct Connection * conn
Definition: adata.h:63
char * authenticators
Definition: adata.h:53
Log at debug level 1.
Definition: logging.h:40
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:749
#define mutt_message(...)
Definition: logging.h:87
int mutt_socket_readln_d(char *buf, size_t buflen, struct Connection *conn, int dbg)
Read a line from a socket.
Definition: socket.c:246
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
bool hasCAPABILITIES
Definition: adata.h:38
MuttAccountFlags flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition: connaccount.h:59
int mutt_account_getpass(struct ConnAccount *cac)
Fetch password into ConnAccount, if necessary.
Definition: connaccount.c:110
int mutt_sasl_interact(sasl_interact_t *interaction)
Perform an SASL interaction with the user.
Definition: sasl.c:698
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_query()

static int nntp_query ( struct NntpMboxData mdata,
char *  line,
size_t  linelen 
)
static

Send data from buffer and receive answer to same buffer.

Parameters
mdataNNTP Mailbox data
lineBuffer containing data
linelenLength of buffer
Return values
0Success
-1Failure

Definition at line 691 of file nntp.c.

692 {
693  struct NntpAccountData *adata = mdata->adata;
694  char buf[1024] = { 0 };
695 
696  if (adata->status == NNTP_BYE)
697  return -1;
698 
699  while (true)
700  {
701  if (adata->status == NNTP_OK)
702  {
703  int rc = 0;
704 
705  if (*line)
706  rc = mutt_socket_send(adata->conn, line);
707  else if (mdata->group)
708  {
709  snprintf(buf, sizeof(buf), "GROUP %s\r\n", mdata->group);
710  rc = mutt_socket_send(adata->conn, buf);
711  }
712  if (rc >= 0)
713  rc = mutt_socket_readln(buf, sizeof(buf), adata->conn);
714  if (rc >= 0)
715  break;
716  }
717 
718  /* reconnect */
719  while (true)
720  {
721  adata->status = NNTP_NONE;
722  if (nntp_open_connection(adata) == 0)
723  break;
724 
725  snprintf(buf, sizeof(buf), _("Connection to %s lost. Reconnect?"),
726  adata->conn->account.host);
727  if (mutt_yesorno(buf, MUTT_YES) != MUTT_YES)
728  {
729  adata->status = NNTP_BYE;
730  return -1;
731  }
732  }
733 
734  /* select newsgroup after reconnection */
735  if (mdata->group)
736  {
737  snprintf(buf, sizeof(buf), "GROUP %s\r\n", mdata->group);
738  if ((mutt_socket_send(adata->conn, buf) < 0) ||
739  (mutt_socket_readln(buf, sizeof(buf), adata->conn) < 0))
740  {
741  return nntp_connect_error(adata);
742  }
743  }
744  if (*line == '\0')
745  break;
746  }
747 
748  mutt_str_copy(line, buf, linelen);
749  return 0;
750 }
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:40
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:37
Disconnected from server.
Definition: private.h:46
struct NntpAccountData * adata
Definition: mdata.h:47
#define _(a)
Definition: message.h:28
static int nntp_connect_error(struct NntpAccountData *adata)
Signal a failed connection.
Definition: nntp.c:127
NNTP-specific Account data -.
Definition: adata.h:36
Connected to server.
Definition: private.h:45
char host[128]
Server to login to.
Definition: connaccount.h:53
char * group
Definition: mdata.h:34
unsigned int status
Definition: adata.h:48
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
No connection to server.
Definition: private.h:44
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:180
#define mutt_socket_readln(buf, buflen, conn)
Definition: mutt_socket.h:36
struct Connection * conn
Definition: adata.h:63
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:749
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
int nntp_open_connection(struct NntpAccountData *adata)
Connect to server, authenticate and get capabilities.
Definition: nntp.c:1712
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_fetch_lines()

static int nntp_fetch_lines ( struct NntpMboxData mdata,
char *  query,
size_t  qlen,
const char *  msg,
int(*)(char *, void *)  func,
void *  data 
)
static

Read lines, calling a callback function for each.

Parameters
mdataNNTP Mailbox data
queryQuery to match
qlenLength of query
msgProgress message (OPTIONAL)
funcCallback function
dataData for callback function
Return values
0Success
1Bad response (answer in query buffer)
-1Connection lost
-2Error in func(*line, *data)

This function calls func(*line, *data) for each received line, func(NULL, *data) if rewind(*data) needs, exits when fail or done:

Definition at line 768 of file nntp.c.

770 {
771  bool done = false;
772  int rc;
773 
774  while (!done)
775  {
776  char buf[1024];
777  char *line = NULL;
778  unsigned int lines = 0;
779  size_t off = 0;
780  struct Progress *progress = NULL;
781 
782  mutt_str_copy(buf, query, sizeof(buf));
783  if (nntp_query(mdata, buf, sizeof(buf)) < 0)
784  return -1;
785  if (buf[0] != '2')
786  {
787  mutt_str_copy(query, buf, qlen);
788  return 1;
789  }
790 
791  line = mutt_mem_malloc(sizeof(buf));
792  rc = 0;
793 
794  if (msg)
795  progress = progress_new(msg, MUTT_PROGRESS_READ, 0);
796 
797  while (true)
798  {
799  char *p = NULL;
800  int chunk = mutt_socket_readln_d(buf, sizeof(buf), mdata->adata->conn, MUTT_SOCK_LOG_FULL);
801  if (chunk < 0)
802  {
803  mdata->adata->status = NNTP_NONE;
804  break;
805  }
806 
807  p = buf;
808  if (!off && (buf[0] == '.'))
809  {
810  if (buf[1] == '\0')
811  {
812  done = true;
813  break;
814  }
815  if (buf[1] == '.')
816  p++;
817  }
818 
819  mutt_str_copy(line + off, p, sizeof(buf));
820 
821  if (chunk >= sizeof(buf))
822  off += strlen(p);
823  else
824  {
825  if (msg)
826  progress_update(progress, ++lines, -1);
827 
828  if ((rc == 0) && (func(line, data) < 0))
829  rc = -2;
830  off = 0;
831  }
832 
833  mutt_mem_realloc(&line, off + sizeof(buf));
834  }
835  FREE(&line);
836  func(NULL, data);
837  progress_free(&progress);
838  }
839 
840  return rc;
841 }
struct NntpAccountData * adata
Definition: mdata.h:47
Progress tracks elements, according to $read_inc
Definition: lib.h:46
#define MUTT_SOCK_LOG_FULL
Definition: mutt_socket.h:31
A Progress Bar.
Definition: progress.c:47
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
unsigned int status
Definition: adata.h:48
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
No connection to server.
Definition: private.h:44
char msg[1024]
Message to display.
Definition: progress.c:50
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:228
void progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:175
struct Connection * conn
Definition: adata.h:63
static int nntp_query(struct NntpMboxData *mdata, char *line, size_t linelen)
Send data from buffer and receive answer to same buffer.
Definition: nntp.c:691
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:749
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:246
#define FREE(x)
Definition: memory.h:40
int mutt_socket_readln_d(char *buf, size_t buflen, struct Connection *conn, int dbg)
Read a line from a socket.
Definition: socket.c:246
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fetch_description()

static int fetch_description ( char *  line,
void *  data 
)
static

Parse newsgroup description.

Parameters
lineString to parse
dataNNTP Server
Return values
0Always

Definition at line 849 of file nntp.c.

850 {
851  if (!line)
852  return 0;
853 
854  struct NntpAccountData *adata = data;
855 
856  char *desc = strpbrk(line, " \t");
857  if (desc)
858  {
859  *desc++ = '\0';
860  desc += strspn(desc, " \t");
861  }
862  else
863  desc = strchr(line, '\0');
864 
865  struct NntpMboxData *mdata = mutt_hash_find(adata->groups_hash, line);
866  if (mdata && !mutt_str_equal(desc, mdata->desc))
867  {
868  mutt_str_replace(&mdata->desc, desc);
869  mutt_debug(LL_DEBUG2, "group: %s, desc: %s\n", line, desc);
870  }
871  return 0;
872 }
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:354
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
struct HashTable * groups_hash
Definition: adata.h:62
NNTP-specific Account data -.
Definition: adata.h:36
Log at debug level 2.
Definition: logging.h:41
void * mdata
Driver specific data.
Definition: mailbox.h:136
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
NNTP-specific Mailbox data -.
Definition: mdata.h:32
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
char * desc
Definition: mdata.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_description()

static int get_description ( struct NntpMboxData mdata,
const char *  wildmat,
const char *  msg 
)
static

Fetch newsgroups descriptions.

Parameters
mdataNNTP Mailbox data
wildmatString to match
msgProgress message
Return values
0Success
1Bad response (answer in query buffer)
-1Connection lost
-2Error

Definition at line 884 of file nntp.c.

885 {
886  char buf[256];
887  const char *cmd = NULL;
888 
889  /* get newsgroup description, if possible */
890  struct NntpAccountData *adata = mdata->adata;
891  if (!wildmat)
892  wildmat = mdata->group;
893  if (adata->hasLIST_NEWSGROUPS)
894  cmd = "LIST NEWSGROUPS";
895  else if (adata->hasXGTITLE)
896  cmd = "XGTITLE";
897  else
898  return 0;
899 
900  snprintf(buf, sizeof(buf), "%s %s\r\n", cmd, wildmat);
901  int rc = nntp_fetch_lines(mdata, buf, sizeof(buf), msg, fetch_description, adata);
902  if (rc > 0)
903  {
904  mutt_error("%s: %s", cmd, buf);
905  }
906  return rc;
907 }
#define mutt_error(...)
Definition: logging.h:88
struct NntpAccountData * adata
Definition: mdata.h:47
static int fetch_description(char *line, void *data)
Parse newsgroup description.
Definition: nntp.c:849
NNTP-specific Account data -.
Definition: adata.h:36
bool hasLIST_NEWSGROUPS
Definition: adata.h:41
char * group
Definition: mdata.h:34
bool hasXGTITLE
Definition: adata.h:42
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
static int nntp_fetch_lines(struct NntpMboxData *mdata, char *query, size_t qlen, const char *msg, int(*func)(char *, void *), void *data)
Read lines, calling a callback function for each.
Definition: nntp.c:768
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_parse_xref()

static void nntp_parse_xref ( struct Mailbox m,
struct Email e 
)
static

Parse cross-reference.

Parameters
mMailbox
eEmail

Update read flag and set article number if empty

Definition at line 916 of file nntp.c.

917 {
918  struct NntpMboxData *mdata = m->mdata;
919 
920  char *buf = mutt_str_dup(e->env->xref);
921  char *p = buf;
922  while (p)
923  {
924  anum_t anum;
925 
926  /* skip to next word */
927  p += strspn(p, " \t");
928  char *grp = p;
929 
930  /* skip to end of word */
931  p = strpbrk(p, " \t");
932  if (p)
933  *p++ = '\0';
934 
935  /* find colon */
936  char *colon = strchr(grp, ':');
937  if (!colon)
938  continue;
939  *colon++ = '\0';
940  if (sscanf(colon, ANUM, &anum) != 1)
941  continue;
942 
943  nntp_article_status(m, e, grp, anum);
944  if (!nntp_edata_get(e)->article_num && mutt_str_equal(mdata->group, grp))
945  nntp_edata_get(e)->article_num = anum;
946  }
947  FREE(&buf);
948 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
char * xref
List of cross-references.
Definition: envelope.h:76
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
anum_t article_num
Definition: edata.h:36
struct Envelope * env
Envelope information.
Definition: email.h:90
char * group
Definition: mdata.h:34
void * mdata
Driver specific data.
Definition: mailbox.h:136
#define ANUM
Definition: lib.h:61
struct NntpEmailData * nntp_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:58
NNTP-specific Mailbox data -.
Definition: mdata.h:32
#define FREE(x)
Definition: memory.h:40
#define anum_t
Definition: lib.h:60
void nntp_article_status(struct Mailbox *m, struct Email *e, char *group, anum_t anum)
Get status of articles from .newsrc.
Definition: newsrc.c:1219
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fetch_tempfile()

static int fetch_tempfile ( char *  line,
void *  data 
)
static

Write line to temporary file.

Parameters
lineText to write
dataFILE pointer
Return values
0Success
-1Failure

Definition at line 957 of file nntp.c.

958 {
959  FILE *fp = data;
960 
961  if (!line)
962  rewind(fp);
963  else if ((fputs(line, fp) == EOF) || (fputc('\n', fp) == EOF))
964  return -1;
965  return 0;
966 }
+ Here is the caller graph for this function:

◆ fetch_numbers()

static int fetch_numbers ( char *  line,
void *  data 
)
static

Parse article number.

Parameters
lineArticle number
dataFetchCtx
Return values
0Always

Definition at line 974 of file nntp.c.

975 {
976  struct FetchCtx *fc = data;
977  anum_t anum;
978 
979  if (!line)
980  return 0;
981  if (sscanf(line, ANUM, &anum) != 1)
982  return 0;
983  if ((anum < fc->first) || (anum > fc->last))
984  return 0;
985  fc->messages[anum - fc->first] = 1;
986  return 0;
987 }
unsigned char * messages
Definition: nntp.c:98
anum_t last
Definition: nntp.c:96
#define ANUM
Definition: lib.h:61
Keep track when getting data from a server.
Definition: nntp.c:92
#define anum_t
Definition: lib.h:60
anum_t first
Definition: nntp.c:95
+ Here is the caller graph for this function:

◆ parse_overview_line()

static int parse_overview_line ( char *  line,
void *  data 
)
static

Parse overview line.

Parameters
lineString to parse
dataFetchCtx
Return values
0Success
-1Failure

Definition at line 996 of file nntp.c.

997 {
998  if (!line || !data)
999  return 0;
1000 
1001  struct FetchCtx *fc = data;
1002  struct Mailbox *m = fc->mailbox;
1003  if (!m)
1004  return -1;
1005 
1006  struct NntpMboxData *mdata = m->mdata;
1007  struct Email *e = NULL;
1008  char *header = NULL, *field = NULL;
1009  bool save = true;
1010  anum_t anum;
1011 
1012  /* parse article number */
1013  field = strchr(line, '\t');
1014  if (field)
1015  *field++ = '\0';
1016  if (sscanf(line, ANUM, &anum) != 1)
1017  return 0;
1018  mutt_debug(LL_DEBUG2, "" ANUM "\n", anum);
1019 
1020  /* out of bounds */
1021  if ((anum < fc->first) || (anum > fc->last))
1022  return 0;
1023 
1024  /* not in LISTGROUP */
1025  if (!fc->messages[anum - fc->first])
1026  {
1027  /* progress */
1028  if (m->verbose)
1029  progress_update(fc->progress, anum - fc->first + 1, -1);
1030  return 0;
1031  }
1032 
1033  /* convert overview line to header */
1034  FILE *fp = mutt_file_mkstemp();
1035  if (!fp)
1036  return -1;
1037 
1038  header = mdata->adata->overview_fmt;
1039  while (field)
1040  {
1041  char *b = field;
1042 
1043  if (*header)
1044  {
1045  if (!strstr(header, ":full") && (fputs(header, fp) == EOF))
1046  {
1047  mutt_file_fclose(&fp);
1048  return -1;
1049  }
1050  header = strchr(header, '\0') + 1;
1051  }
1052 
1053  field = strchr(field, '\t');
1054  if (field)
1055  *field++ = '\0';
1056  if ((fputs(b, fp) == EOF) || (fputc('\n', fp) == EOF))
1057  {
1058  mutt_file_fclose(&fp);
1059  return -1;
1060  }
1061  }
1062  rewind(fp);
1063 
1064  /* allocate memory for headers */
1065  if (m->msg_count >= m->email_max)
1066  mx_alloc_memory(m);
1067 
1068  /* parse header */
1069  m->emails[m->msg_count] = email_new();
1070  e = m->emails[m->msg_count];
1071  e->env = mutt_rfc822_read_header(fp, e, false, false);
1072  e->env->newsgroups = mutt_str_dup(mdata->group);
1073  e->received = e->date_sent;
1074  mutt_file_fclose(&fp);
1075 
1076 #ifdef USE_HCACHE
1077  if (fc->hc)
1078  {
1079  char buf[16];
1080 
1081  /* try to replace with header from cache */
1082  snprintf(buf, sizeof(buf), "%u", anum);
1083  struct HCacheEntry hce = mutt_hcache_fetch(fc->hc, buf, strlen(buf), 0);
1084  if (hce.email)
1085  {
1086  mutt_debug(LL_DEBUG2, "mutt_hcache_fetch %s\n", buf);
1087  email_free(&e);
1088  e = hce.email;
1089  m->emails[m->msg_count] = e;
1090  e->edata = NULL;
1091  e->read = false;
1092  e->old = false;
1093 
1094  /* skip header marked as deleted in cache */
1095  if (e->deleted && !fc->restore)
1096  {
1097  if (mdata->bcache)
1098  {
1099  mutt_debug(LL_DEBUG2, "mutt_bcache_del %s\n", buf);
1100  mutt_bcache_del(mdata->bcache, buf);
1101  }
1102  save = false;
1103  }
1104  }
1105 
1106  /* not cached yet, store header */
1107  else
1108  {
1109  mutt_debug(LL_DEBUG2, "mutt_hcache_store %s\n", buf);
1110  mutt_hcache_store(fc->hc, buf, strlen(buf), e, 0);
1111  }
1112  }
1113 #endif
1114 
1115  if (save)
1116  {
1117  e->index = m->msg_count++;
1118  e->read = false;
1119  e->old = false;
1120  e->deleted = false;
1121  e->edata = nntp_edata_new();
1123  nntp_edata_get(e)->article_num = anum;
1124  if (fc->restore)
1125  e->changed = true;
1126  else
1127  {
1128  nntp_article_status(m, e, NULL, anum);
1129  if (!e->read)
1130  nntp_parse_xref(m, e);
1131  }
1132  if (anum > mdata->last_loaded)
1133  mdata->last_loaded = anum;
1134  }
1135  else
1136  email_free(&e);
1137 
1138  /* progress */
1139  if (m->verbose)
1140  progress_update(fc->progress, anum - fc->first + 1, -1);
1141  return 0;
1142 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
struct HeaderCache * hc
Definition: nntp.c:100
int msg_count
Total number of messages.
Definition: mailbox.h:91
The envelope/body of an email.
Definition: email.h:37
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
Wrapper for Email retrieved from the header cache.
Definition: lib.h:95
static void nntp_parse_xref(struct Mailbox *m, struct Email *e)
Parse cross-reference.
Definition: nntp.c:916
struct NntpAccountData * adata
Definition: mdata.h:47
struct Mailbox * mailbox
Definition: nntp.c:94
void mx_alloc_memory(struct Mailbox *m)
Create storage for the emails.
Definition: mx.c:1212
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
anum_t article_num
Definition: edata.h:36
bool changed
Email has been edited.
Definition: email.h:48
unsigned char * messages
Definition: nntp.c:98
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
bool read
Email is read.
Definition: email.h:51
Log at debug level 2.
Definition: logging.h:41
bool old
Email is seen, but unread.
Definition: email.h:50
struct Progress * progress
Definition: nntp.c:99
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
anum_t last_loaded
Definition: mdata.h:38
anum_t last
Definition: nntp.c:96
struct Envelope * env
Envelope information.
Definition: email.h:90
char * overview_fmt
Definition: adata.h:54
char * group
Definition: mdata.h:34
void * mdata
Driver specific data.
Definition: mailbox.h:136
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:82
#define ANUM
Definition: lib.h:61
void nntp_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: edata.c:38
int email_max
Number of pointers in emails.
Definition: mailbox.h:100
struct BodyCache * bcache
Definition: mdata.h:49
A mailbox.
Definition: mailbox.h:81
void(* edata_free)(void **ptr)
Free the private data attached to the Email.
Definition: email.h:121
struct NntpEmailData * nntp_edata_new(void)
Create a new NntpEmailData for an Email.
Definition: edata.c:48
#define mutt_file_mkstemp()
Definition: file.h:108
bool verbose
Display status messages?
Definition: mailbox.h:118
int mutt_hcache_store(struct HeaderCache *hc, const char *key, size_t keylen, struct Email *e, uint32_t uidvalidity)
Multiplexor for StoreOps::store.
Definition: hcache.c:556
int mutt_bcache_del(struct BodyCache *bcache, const char *id)
Delete a file from the Body Cache.
Definition: bcache.c:264
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
struct NntpEmailData * nntp_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:58
NNTP-specific Mailbox data -.
Definition: mdata.h:32
void progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:175
Keep track when getting data from a server.
Definition: nntp.c:92
char * newsgroups
List of newsgroups.
Definition: envelope.h:75
bool deleted
Email is deleted.
Definition: email.h:45
void * edata
Driver-specific data.
Definition: email.h:111
int index
The absolute (unsorted) message number.
Definition: email.h:86
bool restore
Definition: nntp.c:97
struct HCacheEntry mutt_hcache_fetch(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:461
struct Email * email
Retrieved email.
Definition: lib.h:99
#define anum_t
Definition: lib.h:60
anum_t first
Definition: nntp.c:95
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
parses an RFC822 header
Definition: parse.c:1124
void nntp_article_status(struct Mailbox *m, struct Email *e, char *group, anum_t anum)
Get status of articles from .newsrc.
Definition: newsrc.c:1219
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:83
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_fetch_headers()

static int nntp_fetch_headers ( struct Mailbox m,
void *  hc,
anum_t  first,
anum_t  last,
bool  restore 
)
static

Fetch headers.

Parameters
mMailbox
hcHeader cache
firstNumber of first header to fetch
lastNumber of last header to fetch
restoreRestore message listed as deleted
Return values
0Success
-1Failure

Definition at line 1154 of file nntp.c.

1155 {
1156  if (!m)
1157  return -1;
1158 
1159  struct NntpMboxData *mdata = m->mdata;
1160  struct FetchCtx fc;
1161  struct Email *e = NULL;
1162  char buf[8192];
1163  int rc = 0;
1164  anum_t current;
1165  anum_t first_over = first;
1166 
1167  /* if empty group or nothing to do */
1168  if (!last || (first > last))
1169  return 0;
1170 
1171  /* init fetch context */
1172  fc.mailbox = m;
1173  fc.first = first;
1174  fc.last = last;
1175  fc.restore = restore;
1176  fc.messages = mutt_mem_calloc(last - first + 1, sizeof(unsigned char));
1177  if (!fc.messages)
1178  return -1;
1179  fc.hc = hc;
1180 
1181  /* fetch list of articles */
1182  const bool c_nntp_listgroup = cs_subset_bool(NeoMutt->sub, "nntp_listgroup");
1183  if (c_nntp_listgroup && mdata->adata->hasLISTGROUP && !mdata->deleted)
1184  {
1185  if (m->verbose)
1186  mutt_message(_("Fetching list of articles..."));
1187  if (mdata->adata->hasLISTGROUPrange)
1188  snprintf(buf, sizeof(buf), "LISTGROUP %s %u-%u\r\n", mdata->group, first, last);
1189  else
1190  snprintf(buf, sizeof(buf), "LISTGROUP %s\r\n", mdata->group);
1191  rc = nntp_fetch_lines(mdata, buf, sizeof(buf), NULL, fetch_numbers, &fc);
1192  if (rc > 0)
1193  {
1194  mutt_error("LISTGROUP: %s", buf);
1195  }
1196  if (rc == 0)
1197  {
1198  for (current = first; (current <= last) && (rc == 0); current++)
1199  {
1200  if (fc.messages[current - first])
1201  continue;
1202 
1203  snprintf(buf, sizeof(buf), "%u", current);
1204  if (mdata->bcache)
1205  {
1206  mutt_debug(LL_DEBUG2, "#1 mutt_bcache_del %s\n", buf);
1207  mutt_bcache_del(mdata->bcache, buf);
1208  }
1209 
1210 #ifdef USE_HCACHE
1211  if (fc.hc)
1212  {
1213  mutt_debug(LL_DEBUG2, "mutt_hcache_delete_record %s\n", buf);
1214  mutt_hcache_delete_record(fc.hc, buf, strlen(buf));
1215  }
1216 #endif
1217  }
1218  }
1219  }
1220  else
1221  {
1222  for (current = first; current <= last; current++)
1223  fc.messages[current - first] = 1;
1224  }
1225 
1226  /* fetching header from cache or server, or fallback to fetch overview */
1227  if (m->verbose)
1228  {
1229  fc.progress = progress_new(_("Fetching message headers..."),
1230  MUTT_PROGRESS_READ, last - first + 1);
1231  }
1232  for (current = first; (current <= last) && (rc == 0); current++)
1233  {
1234  if (m->verbose)
1235  progress_update(fc.progress, current - first + 1, -1);
1236 
1237 #ifdef USE_HCACHE
1238  snprintf(buf, sizeof(buf), "%u", current);
1239 #endif
1240 
1241  /* delete header from cache that does not exist on server */
1242  if (!fc.messages[current - first])
1243  continue;
1244 
1245  /* allocate memory for headers */
1246  if (m->msg_count >= m->email_max)
1247  mx_alloc_memory(m);
1248 
1249 #ifdef USE_HCACHE
1250  /* try to fetch header from cache */
1251  struct HCacheEntry hce = mutt_hcache_fetch(fc.hc, buf, strlen(buf), 0);
1252  if (hce.email)
1253  {
1254  mutt_debug(LL_DEBUG2, "mutt_hcache_fetch %s\n", buf);
1255  e = hce.email;
1256  m->emails[m->msg_count] = e;
1257  e->edata = NULL;
1258 
1259  /* skip header marked as deleted in cache */
1260  if (e->deleted && !restore)
1261  {
1262  email_free(&e);
1263  if (mdata->bcache)
1264  {
1265  mutt_debug(LL_DEBUG2, "#2 mutt_bcache_del %s\n", buf);
1266  mutt_bcache_del(mdata->bcache, buf);
1267  }
1268  continue;
1269  }
1270 
1271  e->read = false;
1272  e->old = false;
1273  }
1274  else
1275 #endif
1276  if (mdata->deleted)
1277  {
1278  /* don't try to fetch header from removed newsgroup */
1279  continue;
1280  }
1281 
1282  /* fallback to fetch overview */
1283  else if (mdata->adata->hasOVER || mdata->adata->hasXOVER)
1284  {
1285  if (c_nntp_listgroup && mdata->adata->hasLISTGROUP)
1286  break;
1287  else
1288  continue;
1289  }
1290 
1291  /* fetch header from server */
1292  else
1293  {
1294  FILE *fp = mutt_file_mkstemp();
1295  if (!fp)
1296  {
1297  mutt_perror(_("Can't create temporary file"));
1298  rc = -1;
1299  break;
1300  }
1301 
1302  snprintf(buf, sizeof(buf), "HEAD %u\r\n", current);
1303  rc = nntp_fetch_lines(mdata, buf, sizeof(buf), NULL, fetch_tempfile, fp);
1304  if (rc)
1305  {
1306  mutt_file_fclose(&fp);
1307  if (rc < 0)
1308  break;
1309 
1310  /* invalid response */
1311  if (!mutt_str_startswith(buf, "423"))
1312  {
1313  mutt_error("HEAD: %s", buf);
1314  break;
1315  }
1316 
1317  /* no such article */
1318  if (mdata->bcache)
1319  {
1320  snprintf(buf, sizeof(buf), "%u", current);
1321  mutt_debug(LL_DEBUG2, "#3 mutt_bcache_del %s\n", buf);
1322  mutt_bcache_del(mdata->bcache, buf);
1323  }
1324  rc = 0;
1325  continue;
1326  }
1327 
1328  /* parse header */
1329  m->emails[m->msg_count] = email_new();
1330  e = m->emails[m->msg_count];
1331  e->env = mutt_rfc822_read_header(fp, e, false, false);
1332  e->received = e->date_sent;
1333  mutt_file_fclose(&fp);
1334  }
1335 
1336  /* save header in context */
1337  e->index = m->msg_count++;
1338  e->read = false;
1339  e->old = false;
1340  e->deleted = false;
1341  e->edata = nntp_edata_new();
1343  nntp_edata_get(e)->article_num = current;
1344  if (restore)
1345  e->changed = true;
1346  else
1347  {
1348  nntp_article_status(m, e, NULL, nntp_edata_get(e)->article_num);
1349  if (!e->read)
1350  nntp_parse_xref(m, e);
1351  }
1352  if (current > mdata->last_loaded)
1353  mdata->last_loaded = current;
1354  first_over = current + 1;
1355  }
1356 
1357  if (!c_nntp_listgroup || !mdata->adata->hasLISTGROUP)
1358  current = first_over;
1359 
1360  /* fetch overview information */
1361  if ((current <= last) && (rc == 0) && !mdata->deleted)
1362  {
1363  char *cmd = mdata->adata->hasOVER ? "OVER" : "XOVER";
1364  snprintf(buf, sizeof(buf), "%s %u-%u\r\n", cmd, current, last);
1365  rc = nntp_fetch_lines(mdata, buf, sizeof(buf), NULL, parse_overview_line, &fc);
1366  if (rc > 0)
1367  {
1368  mutt_error("%s: %s", cmd, buf);
1369  }
1370  }
1371 
1372  FREE(&fc.messages);
1373  progress_free(&fc.progress);
1374  if (rc != 0)
1375  return -1;
1376  mutt_clear_error();
1377  return 0;
1378 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
int msg_count
Total number of messages.
Definition: mailbox.h:91
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
The envelope/body of an email.
Definition: email.h:37
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
Wrapper for Email retrieved from the header cache.
Definition: lib.h:95
static void nntp_parse_xref(struct Mailbox *m, struct Email *e)
Parse cross-reference.
Definition: nntp.c:916
#define mutt_error(...)
Definition: logging.h:88
struct NntpAccountData * adata
Definition: mdata.h:47
static int fetch_tempfile(char *line, void *data)
Write line to temporary file.
Definition: nntp.c:957
void mx_alloc_memory(struct Mailbox *m)
Create storage for the emails.
Definition: mx.c:1212
#define _(a)
Definition: message.h:28
Progress tracks elements, according to $read_inc
Definition: lib.h:46
anum_t article_num
Definition: edata.h:36
bool changed
Email has been edited.
Definition: email.h:48
#define mutt_perror(...)
Definition: logging.h:89
Container for Accounts, Notifications.
Definition: neomutt.h:36
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
bool read
Email is read.
Definition: email.h:51
Log at debug level 2.
Definition: logging.h:41
bool old
Email is seen, but unread.
Definition: email.h:50
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
anum_t last_loaded
Definition: mdata.h:38
struct Envelope * env
Envelope information.
Definition: email.h:90
char * group
Definition: mdata.h:34
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:112
void * mdata
Driver specific data.
Definition: mailbox.h:136
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:82
void nntp_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: edata.c:38
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
int email_max
Number of pointers in emails.
Definition: mailbox.h:100
struct BodyCache * bcache
Definition: mdata.h:49
bool hasLISTGROUP
Definition: adata.h:43
void(* edata_free)(void **ptr)
Free the private data attached to the Email.
Definition: email.h:121
int mutt_hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:637
struct NntpEmailData * nntp_edata_new(void)
Create a new NntpEmailData for an Email.
Definition: edata.c:48
#define mutt_file_mkstemp()
Definition: file.h:108
bool verbose
Display status messages?
Definition: mailbox.h:118
int mutt_bcache_del(struct BodyCache *bcache, const char *id)
Delete a file from the Body Cache.
Definition: bcache.c:264
static int fetch_numbers(char *line, void *data)
Parse article number.
Definition: nntp.c:974
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
struct NntpEmailData * nntp_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:58
bool hasOVER
Definition: adata.h:45
NNTP-specific Mailbox data -.
Definition: mdata.h:32
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:228
void progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:175
static int nntp_fetch_lines(struct NntpMboxData *mdata, char *query, size_t qlen, const char *msg, int(*func)(char *, void *), void *data)
Read lines, calling a callback function for each.
Definition: nntp.c:768
Keep track when getting data from a server.
Definition: nntp.c:92
bool deleted
Definition: mdata.h:44
bool hasLISTGROUPrange
Definition: adata.h:44
bool deleted
Email is deleted.
Definition: email.h:45
void * edata
Driver-specific data.
Definition: email.h:111
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:246
int index
The absolute (unsorted) message number.
Definition: email.h:86
#define mutt_message(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:40
struct HCacheEntry mutt_hcache_fetch(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:461
bool hasXOVER
Definition: adata.h:46
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
struct Email * email
Retrieved email.
Definition: lib.h:99
#define anum_t
Definition: lib.h:60
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
parses an RFC822 header
Definition: parse.c:1124
void nntp_article_status(struct Mailbox *m, struct Email *e, char *group, anum_t anum)
Get status of articles from .newsrc.
Definition: newsrc.c:1219
static int parse_overview_line(char *line, void *data)
Parse overview line.
Definition: nntp.c:996
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:83
static struct Email * restore(const unsigned char *d)
Restore an Email from data retrieved from the cache.
Definition: hcache.c:143
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_group_poll()

static int nntp_group_poll ( struct NntpMboxData mdata,
bool  update_stat 
)
static

Check newsgroup for new articles.

Parameters
mdataNNTP Mailbox data
update_statUpdate the stats?
Return values
1New articles found
0No change
-1Lost connection

Definition at line 1388 of file nntp.c.

1389 {
1390  char buf[1024] = { 0 };
1391  anum_t count, first, last;
1392 
1393  /* use GROUP command to poll newsgroup */
1394  if (nntp_query(mdata, buf, sizeof(buf)) < 0)
1395  return -1;
1396  if (sscanf(buf, "211 " ANUM " " ANUM " " ANUM, &count, &first, &last) != 3)
1397  return 0;
1398  if ((first == mdata->first_message) && (last == mdata->last_message))
1399  return 0;
1400 
1401  /* articles have been renumbered */
1402  if (last < mdata->last_message)
1403  {
1404  mdata->last_cached = 0;
1405  if (mdata->newsrc_len)
1406  {
1407  mutt_mem_realloc(&mdata->newsrc_ent, sizeof(struct NewsrcEntry));
1408  mdata->newsrc_len = 1;
1409  mdata->newsrc_ent[0].first = 1;
1410  mdata->newsrc_ent[0].last = 0;
1411  }
1412  }
1413  mdata->first_message = first;
1414  mdata->last_message = last;
1415  if (!update_stat)
1416  return 1;
1417 
1418  /* update counters */
1419  else if (!last || (!mdata->newsrc_ent && !mdata->last_cached))
1420  mdata->unread = count;
1421  else
1422  nntp_group_unread_stat(mdata);
1423  return 1;
1424 }
anum_t last
Definition: lib.h:78
anum_t last_cached
Definition: mdata.h:39
An entry in a .newsrc (subscribed newsgroups)
Definition: lib.h:75
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
#define ANUM
Definition: lib.h:61
struct NewsrcEntry * newsrc_ent
Definition: mdata.h:46
unsigned int newsrc_len
Definition: mdata.h:45
static int nntp_query(struct NntpMboxData *mdata, char *line, size_t linelen)
Send data from buffer and receive answer to same buffer.
Definition: nntp.c:691
anum_t first_message
Definition: mdata.h:36
anum_t unread
Definition: mdata.h:40
void nntp_group_unread_stat(struct NntpMboxData *mdata)
Count number of unread articles using .newsrc data.
Definition: newsrc.c:132
#define anum_t
Definition: lib.h:60
anum_t first
Definition: lib.h:77
anum_t last_message
Definition: mdata.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_mailbox()

static enum MxStatus check_mailbox ( struct Mailbox m)
static

Check current newsgroup for new articles.

Parameters
mMailbox
Return values
enumMxStatus

Leave newsrc locked

Definition at line 1433 of file nntp.c.

1434 {
1435  if (!m)
1436  return MX_STATUS_ERROR;
1437 
1438  struct NntpMboxData *mdata = m->mdata;
1439  struct NntpAccountData *adata = mdata->adata;
1440  time_t now = mutt_date_epoch();
1441  enum MxStatus rc = MX_STATUS_OK;
1442  void *hc = NULL;
1443 
1444  const short c_nntp_poll = cs_subset_number(NeoMutt->sub, "nntp_poll");
1445  if (adata->check_time + c_nntp_poll > now)
1446  return MX_STATUS_OK;
1447 
1448  mutt_message(_("Checking for new messages..."));
1449  if (nntp_newsrc_parse(adata) < 0)
1450  return MX_STATUS_ERROR;
1451 
1452  adata->check_time = now;
1453  int rc2 = nntp_group_poll(mdata, false);
1454  if (rc2 < 0)
1455  {
1456  nntp_newsrc_close(adata);
1457  return -1;
1458  }
1459  if (rc2 != 0)
1460  nntp_active_save_cache(adata);
1461 
1462  /* articles have been renumbered, remove all headers */
1463  if (mdata->last_message < mdata->last_loaded)
1464  {
1465  for (int i = 0; i < m->msg_count; i++)
1466  email_free(&m->emails[i]);
1467  m->msg_count = 0;
1468  m->msg_tagged = 0;
1469 
1470  if (mdata->last_message < mdata->last_loaded)
1471  {
1472  mdata->last_loaded = mdata->first_message - 1;
1473  const short c_nntp_context =
1474  cs_subset_number(NeoMutt->sub, "nntp_context");
1475  if (c_nntp_context && (mdata->last_message - mdata->last_loaded > c_nntp_context))
1476  mdata->last_loaded = mdata->last_message - c_nntp_context;
1477  }
1478  rc = MX_STATUS_REOPENED;
1479  }
1480 
1481  /* .newsrc has been externally modified */
1482  if (adata->newsrc_modified)
1483  {
1484 #ifdef USE_HCACHE
1485  unsigned char *messages = NULL;
1486  char buf[16];
1487  struct Email *e = NULL;
1488  anum_t first = mdata->first_message;
1489 
1490  const short c_nntp_context = cs_subset_number(NeoMutt->sub, "nntp_context");
1491  if (c_nntp_context && (mdata->last_message - first + 1 > c_nntp_context))
1492  first = mdata->last_message - c_nntp_context + 1;
1493  messages = mutt_mem_calloc(mdata->last_loaded - first + 1, sizeof(unsigned char));
1494  hc = nntp_hcache_open(mdata);
1495  nntp_hcache_update(mdata, hc);
1496 #endif
1497 
1498  /* update flags according to .newsrc */
1499  int j = 0;
1500  for (int i = 0; i < m->msg_count; i++)
1501  {
1502  if (!m->emails[i])
1503  continue;
1504  bool flagged = false;
1505  anum_t anum = nntp_edata_get(m->emails[i])->article_num;
1506 
1507 #ifdef USE_HCACHE
1508  /* check hcache for flagged and deleted flags */
1509  if (hc)
1510  {
1511  if ((anum >= first) && (anum <= mdata->last_loaded))
1512  messages[anum - first] = 1;
1513 
1514  snprintf(buf, sizeof(buf), "%u", anum);
1515  struct HCacheEntry hce = mutt_hcache_fetch(hc, buf, strlen(buf), 0);
1516  if (hce.email)
1517  {
1518  bool deleted;
1519 
1520  mutt_debug(LL_DEBUG2, "#1 mutt_hcache_fetch %s\n", buf);
1521  e = hce.email;
1522  e->edata = NULL;
1523  deleted = e->deleted;
1524  flagged = e->flagged;
1525  email_free(&e);
1526 
1527  /* header marked as deleted, removing from context */
1528  if (deleted)
1529  {
1530  mutt_set_flag(m, m->emails[i], MUTT_TAG, false);
1531  email_free(&m->emails[i]);
1532  continue;
1533  }
1534  }
1535  }
1536 #endif
1537 
1538  if (!m->emails[i]->changed)
1539  {
1540  m->emails[i]->flagged = flagged;
1541  m->emails[i]->read = false;
1542  m->emails[i]->old = false;
1543  nntp_article_status(m, m->emails[i], NULL, anum);
1544  if (!m->emails[i]->read)
1545  nntp_parse_xref(m, m->emails[i]);
1546  }
1547  m->emails[j++] = m->emails[i];
1548  }
1549 
1550 #ifdef USE_HCACHE
1551  m->msg_count = j;
1552 
1553  /* restore headers without "deleted" flag */
1554  for (anum_t anum = first; anum <= mdata->last_loaded; anum++)
1555  {
1556  if (messages[anum - first])
1557  continue;
1558 
1559  snprintf(buf, sizeof(buf), "%u", anum);
1560  struct HCacheEntry hce = mutt_hcache_fetch(hc, buf, strlen(buf), 0);
1561  if (hce.email)
1562  {
1563  mutt_debug(LL_DEBUG2, "#2 mutt_hcache_fetch %s\n", buf);
1564  if (m->msg_count >= m->email_max)
1565  mx_alloc_memory(m);
1566 
1567  e = hce.email;
1568  m->emails[m->msg_count] = e;
1569  e->edata = NULL;
1570  if (e->deleted)
1571  {
1572  email_free(&e);
1573  if (mdata->bcache)
1574  {
1575  mutt_debug(LL_DEBUG2, "mutt_bcache_del %s\n", buf);
1576  mutt_bcache_del(mdata->bcache, buf);
1577  }
1578  continue;
1579  }
1580 
1581  m->msg_count++;
1582  e->read = false;
1583  e->old = false;
1584  e->edata = nntp_edata_new();
1586  nntp_edata_get(e)->article_num = anum;
1587  nntp_article_status(m, e, NULL, anum);
1588  if (!e->read)
1589  nntp_parse_xref(m, e);
1590  }
1591  }
1592  FREE(&messages);
1593 #endif
1594 
1595  adata->newsrc_modified = false;
1596  rc = MX_STATUS_REOPENED;
1597  }
1598 
1599  /* some headers were removed, context must be updated */
1600  if (rc == MX_STATUS_REOPENED)
1602 
1603  /* fetch headers of new articles */
1604  if (mdata->last_message > mdata->last_loaded)
1605  {
1606  int oldmsgcount = m->msg_count;
1607  bool verbose = m->verbose;
1608  m->verbose = false;
1609 #ifdef USE_HCACHE
1610  if (!hc)
1611  {
1612  hc = nntp_hcache_open(mdata);
1613  nntp_hcache_update(mdata, hc);
1614  }
1615 #endif
1616  int old_msg_count = m->msg_count;
1617  rc2 = nntp_fetch_headers(m, hc, mdata->last_loaded + 1, mdata->last_message, false);
1618  m->verbose = verbose;
1619  if (rc2 == 0)
1620  {
1621  if (m->msg_count > old_msg_count)
1623  mdata->last_loaded = mdata->last_message;
1624  }
1625  if ((rc == MX_STATUS_OK) && (m->msg_count > oldmsgcount))
1626  rc = MX_STATUS_NEW_MAIL;
1627  }
1628 
1629 #ifdef USE_HCACHE
1630  mutt_hcache_close(hc);
1631 #endif
1632  if (rc != MX_STATUS_OK)
1633  nntp_newsrc_close(adata);
1634  mutt_clear_error();
1635  return rc;
1636 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:427
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
int msg_count
Total number of messages.
Definition: mailbox.h:91
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:66
The envelope/body of an email.
Definition: email.h:37
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
Wrapper for Email retrieved from the header cache.
Definition: lib.h:95
static void nntp_parse_xref(struct Mailbox *m, struct Email *e)
Parse cross-reference.
Definition: nntp.c:916
static int nntp_fetch_headers(struct Mailbox *m, void *hc, anum_t first, anum_t last, bool restore)
Fetch headers.
Definition: nntp.c:1154
bool newsrc_modified
Definition: adata.h:50
struct NntpAccountData * adata
Definition: mdata.h:47
New mail received in Mailbox.
Definition: mxapi.h:79
void mx_alloc_memory(struct Mailbox *m)
Create storage for the emails.
Definition: mx.c:1212
#define _(a)
Definition: message.h:28
anum_t article_num
Definition: edata.h:36
bool changed
Email has been edited.
Definition: email.h:48
void nntp_newsrc_close(struct NntpAccountData *adata)
Unlock and close .newsrc file.
Definition: newsrc.c:118
Email list was changed.
Definition: mailbox.h:180
int nntp_active_save_cache(struct NntpAccountData *adata)
Save list of all newsgroups to cache.
Definition: newsrc.c:650
void nntp_hcache_update(struct NntpMboxData *mdata, struct HeaderCache *hc)
Remove stale cached headers.
Definition: newsrc.c:735
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
Container for Accounts, Notifications.
Definition: neomutt.h:36
NNTP-specific Account data -.
Definition: adata.h:36
Mailbox was reopened.
Definition: mxapi.h:81
bool read
Email is read.
Definition: email.h:51
Log at debug level 2.
Definition: logging.h:41
bool old
Email is seen, but unread.
Definition: email.h:50
anum_t last_loaded
Definition: mdata.h:38
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:112
void * mdata
Driver specific data.
Definition: mailbox.h:136
static int nntp_group_poll(struct NntpMboxData *mdata, bool update_stat)
Check newsgroup for new articles.
Definition: nntp.c:1388
void nntp_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: edata.c:38
int email_max
Number of pointers in emails.
Definition: mailbox.h:100
struct BodyCache * bcache
Definition: mdata.h:49
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
struct HeaderCache * nntp_hcache_open(struct NntpMboxData *mdata)
Open newsgroup hcache.
Definition: newsrc.c:709
No changes.
Definition: mxapi.h:78
Tagged messages.
Definition: mutt.h:99
void(* edata_free)(void **ptr)
Free the private data attached to the Email.
Definition: email.h:121
int nntp_newsrc_parse(struct NntpAccountData *adata)
Parse .newsrc file.
Definition: newsrc.c:162
struct NntpEmailData * nntp_edata_new(void)
Create a new NntpEmailData for an Email.
Definition: edata.c:48
bool verbose
Display status messages?
Definition: mailbox.h:118
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:97
int mutt_bcache_del(struct BodyCache *bcache, const char *id)
Delete a file from the Body Cache.
Definition: bcache.c:264
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
struct NntpEmailData * nntp_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:58
NNTP-specific Mailbox data -.
Definition: mdata.h:32
void mutt_hcache_close(struct HeaderCache *hc)
Multiplexor for StoreOps::close.
Definition: hcache.c:435
time_t check_time
Definition: adata.h:58
bool flagged
Marked important?
Definition: email.h:43
anum_t first_message
Definition: mdata.h:36
bool deleted
Email is deleted.
Definition: email.h:45
void * edata
Driver-specific data.
Definition: email.h:111
#define mutt_message(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:40
struct HCacheEntry mutt_hcache_fetch(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition: hcache.c:461
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
struct Email * email
Retrieved email.
Definition: lib.h:99
#define anum_t
Definition: lib.h:60
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:208
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_snc(), and mbox_close() ...
Definition: mxapi.h:75
void nntp_article_status(struct Mailbox *m, struct Email *e, char *group, anum_t anum)
Get status of articles from .newsrc.
Definition: newsrc.c:1219
An error occurred.
Definition: mxapi.h:77
anum_t last_message
Definition: mdata.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_date()

static int nntp_date ( struct NntpAccountData adata,
time_t *  now 
)
static

Get date and time from server.

Parameters
adataNNTP server
nowServer time
Return values
0Success
-1Failure

Definition at line 1645 of file nntp.c.

1646 {
1647  if (adata->hasDATE)
1648  {
1649  struct NntpMboxData mdata = { 0 };
1650  char buf[1024];
1651  struct tm tm = { 0 };
1652 
1653  mdata.adata = adata;
1654  mdata.group = NULL;
1655  mutt_str_copy(buf, "DATE\r\n", sizeof(buf));
1656  if (nntp_query(&mdata, buf, sizeof(buf)) < 0)
1657  return -1;
1658 
1659  if (sscanf(buf, "111 %4d%2d%2d%2d%2d%2d%*s", &tm.tm_year, &tm.tm_mon,
1660  &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6)
1661  {
1662  tm.tm_year -= 1900;
1663  tm.tm_mon--;
1664  *now = timegm(&tm);
1665  if (*now >= 0)
1666  {
1667  mutt_debug(LL_DEBUG1, "server time is %lu\n", *now);
1668  return 0;
1669  }
1670  }
1671  }
1672  *now = mutt_date_epoch();
1673  return 0;
1674 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:427
struct NntpAccountData * adata
Definition: mdata.h:47
char * group
Definition: mdata.h:34
void * mdata
Driver specific data.
Definition: mailbox.h:136
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
NNTP-specific Mailbox data -.
Definition: mdata.h:32
static int nntp_query(struct NntpMboxData *mdata, char *line, size_t linelen)
Send data from buffer and receive answer to same buffer.
Definition: nntp.c:691
Log at debug level 1.
Definition: logging.h:40
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:749
bool hasDATE
Definition: adata.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fetch_children()

static int fetch_children ( char *  line,
void *  data 
)
static

Parse XPAT line.

Parameters
lineString to parse
dataChildCtx
Return values
0Always

Definition at line 1682 of file nntp.c.

1683 {
1684  struct ChildCtx *cc = data;
1685  anum_t anum;
1686 
1687  if (!line || (sscanf(line, ANUM, &anum) != 1))
1688  return 0;
1689  for (unsigned int i = 0; i < cc->mailbox->msg_count; i++)
1690  {
1691  struct Email *e = cc->mailbox->emails[i];
1692  if (!e)
1693  break;
1694  if (nntp_edata_get(e)->article_num == anum)
1695  return 0;
1696  }
1697  if (cc->num >= cc->max)
1698  {
1699  cc->max *= 2;
1700  mutt_mem_realloc(&cc->child, sizeof(anum_t) * cc->max);
1701  }
1702  cc->child[cc->num++] = anum;
1703  return 0;
1704 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
int msg_count
Total number of messages.
Definition: mailbox.h:91
The envelope/body of an email.
Definition: email.h:37
unsigned int num
Definition: nntp.c:109
Keep track of the children of an article.
Definition: nntp.c:106
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
#define ANUM
Definition: lib.h:61
struct Mailbox * mailbox
Definition: nntp.c:108
anum_t * child
Definition: nntp.c:111
struct NntpEmailData * nntp_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:58
unsigned int max
Definition: nntp.c:110
#define anum_t
Definition: lib.h:60
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_open_connection()

int nntp_open_connection ( struct NntpAccountData adata)

Connect to server, authenticate and get capabilities.

Parameters
adataNNTP server
Return values
0Success
-1Failure

Definition at line 1712 of file nntp.c.

1713 {
1714  struct Connection *conn = adata->conn;
1715  char buf[256];
1716  int cap;
1717  bool posting = false, auth = true;
1718 
1719  if (adata->status == NNTP_OK)
1720  return 0;
1721  if (adata->status == NNTP_BYE)
1722  return -1;
1723  adata->status = NNTP_NONE;
1724 
1725  if (mutt_socket_open(conn) < 0)
1726  return -1;
1727 
1728  if (mutt_socket_readln(buf, sizeof(buf), conn) < 0)
1729  return nntp_connect_error(adata);
1730 
1731  if (mutt_str_startswith(buf, "200"))
1732  posting = true;
1733  else if (!mutt_str_startswith(buf, "201"))
1734  {
1735  mutt_socket_close(conn);
1737  mutt_error("%s", buf);
1738  return -1;
1739  }
1740 
1741  /* get initial capabilities */
1742  cap = nntp_capabilities(adata);
1743  if (cap < 0)
1744  return -1;
1745 
1746  /* tell news server to switch to mode reader if it isn't so */
1747  if (cap > 0)
1748  {
1749  if ((mutt_socket_send(conn, "MODE READER\r\n") < 0) ||
1750  (mutt_socket_readln(buf, sizeof(buf), conn) < 0))
1751  {
1752  return nntp_connect_error(adata);
1753  }
1754 
1755  if (mutt_str_startswith(buf, "200"))
1756  posting = true;
1757  else if (mutt_str_startswith(buf, "201"))
1758  posting = false;
1759  /* error if has capabilities, ignore result if no capabilities */
1760  else if (adata->hasCAPABILITIES)
1761  {
1762  mutt_socket_close(conn);
1763  mutt_error(_("Could not switch to reader mode"));
1764  return -1;
1765  }
1766 
1767  /* recheck capabilities after MODE READER */
1768  if (adata->hasCAPABILITIES)
1769  {
1770  cap = nntp_capabilities(adata);
1771  if (cap < 0)
1772  return -1;
1773  }
1774  }
1775 
1776  mutt_message(_("Connected to %s. %s"), conn->account.host,
1777  posting ? _("Posting is ok") : _("Posting is NOT ok"));
1778  mutt_sleep(1);
1779 
1780 #ifdef USE_SSL
1781  /* Attempt STARTTLS if available and desired. */
1782  const bool c_ssl_force_tls = cs_subset_bool(NeoMutt->sub, "ssl_force_tls");
1783  if ((adata->use_tls != 1) && (adata->hasSTARTTLS || c_ssl_force_tls))
1784  {
1785  if (adata->use_tls == 0)
1786  {
1787  const enum QuadOption c_ssl_starttls =
1788  cs_subset_quad(NeoMutt->sub, "ssl_starttls");
1789  adata->use_tls =
1790  c_ssl_force_tls ||
1791  (query_quadoption(c_ssl_starttls,
1792  _("Secure connection with TLS?")) == MUTT_YES) ?
1793  2 :
1794  1;
1795  }
1796  if (adata->use_tls == 2)
1797  {
1798  if ((mutt_socket_send(conn, "STARTTLS\r\n") < 0) ||
1799  (mutt_socket_readln(buf, sizeof(buf), conn) < 0))
1800  {
1801  return nntp_connect_error(adata);
1802  }
1803  // Clear any data after the STARTTLS acknowledgement
1804  mutt_socket_empty(conn);
1805  if (!mutt_str_startswith(buf, "382"))
1806  {
1807  adata->use_tls = 0;
1808  mutt_error("STARTTLS: %s", buf);
1809  }
1810  else if (mutt_ssl_starttls(conn))
1811  {
1812  adata->use_tls = 0;
1813  adata->status = NNTP_NONE;
1814  mutt_socket_close(adata->conn);
1815  mutt_error(_("Could not negotiate TLS connection"));
1816  return -1;
1817  }
1818  else
1819  {
1820  /* recheck capabilities after STARTTLS */
1821  cap = nntp_capabilities(adata);
1822  if (cap < 0)
1823  return -1;
1824  }
1825  }
1826  }
1827 #endif
1828 
1829  /* authentication required? */
1830  if (conn->account.flags & MUTT_ACCT_USER)
1831  {
1832  if (!conn->account.user[0])
1833  auth = false;
1834  }
1835  else
1836  {
1837  if ((mutt_socket_send(conn, "STAT\r\n") < 0) ||
1838  (mutt_socket_readln(buf, sizeof(buf), conn) < 0))
1839  {
1840  return nntp_connect_error(adata);
1841  }
1842  if (!mutt_str_startswith(buf, "480"))
1843  auth = false;
1844  }
1845 
1846  /* authenticate */
1847  if (auth && (nntp_auth(adata) < 0))
1848  return -1;
1849 
1850  /* get final capabilities after authentication */
1851  if (adata->hasCAPABILITIES && (auth || (cap > 0)))
1852  {
1853  cap = nntp_capabilities(adata);
1854  if (cap < 0)
1855  return -1;
1856  if (cap > 0)
1857  {
1858  mutt_socket_close(conn);
1859  mutt_error(_("Could not switch to reader mode"));
1860  return -1;
1861  }
1862  }
1863 
1864  /* attempt features */
1865  if (nntp_attempt_features(adata) < 0)
1866  return -1;
1867 
1868  adata->status = NNTP_OK;
1869  return 0;
1870 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
static int nntp_auth(struct NntpAccountData *adata)
Get login, password and authenticate.
Definition: nntp.c:427
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:40
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:37
#define mutt_error(...)
Definition: logging.h:88
static int nntp_attempt_features(struct NntpAccountData *adata)
Detect supported commands.
Definition: nntp.c:244
Disconnected from server.
Definition: private.h:46
unsigned int use_tls
Definition: adata.h:47
char user[128]
Username.
Definition: connaccount.h:55
#define _(a)
Definition: message.h:28
static int nntp_connect_error(struct NntpAccountData *adata)
Signal a failed connection.
Definition: nntp.c:127
bool hasSTARTTLS
Definition: adata.h:39
Container for Accounts, Notifications.
Definition: neomutt.h:36
#define MUTT_ACCT_USER
User field has been set.
Definition: connaccount.h:43
Connected to server.
Definition: private.h:45
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
int mutt_socket_open(struct Connection *conn)
Simple wrapper.
Definition: socket.c:76
char host[128]
Server to login to.
Definition: connaccount.h:53
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1461
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:347
void mutt_str_remove_trailing_ws(char *s)
Trim trailing whitespace from a string.
Definition: string.c:733
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
unsigned int status
Definition: adata.h:48
No connection to server.
Definition: private.h:44
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition: socket.c:97
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
#define mutt_socket_readln(buf, buflen, conn)
Definition: mutt_socket.h:36
struct Connection * conn
Definition: adata.h:63
void mutt_socket_empty(struct Connection *conn)
Clear out any queued data.
Definition: socket.c:313
#define mutt_message(...)
Definition: logging.h:87
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
bool hasCAPABILITIES
Definition: adata.h:38
int mutt_ssl_starttls(struct Connection *conn)
Negotiate TLS over an already opened connection.
Definition: gnutls.c:1167
static int nntp_capabilities(struct NntpAccountData *adata)
Get capabilities.
Definition: nntp.c:141
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
MuttAccountFlags flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition: connaccount.h:59
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_post()

int nntp_post ( struct Mailbox m,
const char *  msg 
)

Post article.

Parameters
mMailbox
msgMessage to post
Return values
0Success
-1Failure

Definition at line 1879 of file nntp.c.

1880 {
1881  struct NntpMboxData *mdata = NULL;
1882  struct NntpMboxData tmp_mdata = { 0 };
1883  char buf[1024];
1884 
1885  if (m && (m->type == MUTT_NNTP))
1886  mdata = m->mdata;
1887  else
1888  {
1889  const char *const c_news_server =
1890  cs_subset_string(NeoMutt->sub, "news_server");
1891  CurrentNewsSrv = nntp_select_server(m, c_news_server, false);
1892  if (!CurrentNewsSrv)
1893  return -1;
1894 
1895  mdata = &tmp_mdata;
1896  mdata->adata = CurrentNewsSrv;
1897  mdata->group = NULL;
1898  }
1899 
1900  FILE *fp = mutt_file_fopen(msg, "r");
1901  if (!fp)
1902  {
1903  mutt_perror(msg);
1904  return -1;
1905  }
1906 
1907  mutt_str_copy(buf, "POST\r\n", sizeof(buf));
1908  if (nntp_query(mdata, buf, sizeof(buf)) < 0)
1909  {
1910  mutt_file_fclose(&fp);
1911  return -1;
1912  }
1913  if (buf[0] != '3')
1914  {
1915  mutt_error(_("Can't post article: %s"), buf);
1916  mutt_file_fclose(&fp);
1917  return -1;
1918  }
1919 
1920  buf[0] = '.';
1921  buf[1] = '\0';
1922  while (fgets(buf + 1, sizeof(buf) - 2, fp))
1923  {
1924  size_t len = strlen(buf);
1925  if (buf[len - 1] == '\n')
1926  {
1927  buf[len - 1] = '\r';
1928  buf[len] = '\n';
1929  len++;
1930  buf[len] = '\0';
1931  }
1932  if (mutt_socket_send_d(mdata->adata->conn, (buf[1] == '.') ? buf : buf + 1,
1933  MUTT_SOCK_LOG_FULL) < 0)
1934  {
1935  mutt_file_fclose(&fp);
1936  return nntp_connect_error(mdata->adata);
1937  }
1938  }
1939  mutt_file_fclose(&fp);
1940 
1941  if (((buf[strlen(buf) - 1] != '\n') &&
1942  (mutt_socket_send_d(mdata->adata->conn, "\r\n", MUTT_SOCK_LOG_FULL) < 0)) ||
1943  (mutt_socket_send_d(mdata->adata->conn, ".\r\n", MUTT_SOCK_LOG_FULL) < 0) ||
1944  (mutt_socket_readln(buf, sizeof(buf), mdata->adata->conn) < 0))
1945  {
1946  return nntp_connect_error(mdata->adata);
1947  }
1948  if (buf[0] != '2')
1949  {
1950  mutt_error(_("Can't post article: %s"), buf);
1951  return -1;
1952  }
1953  return 0;
1954 }
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:52
#define mutt_error(...)
Definition: logging.h:88
struct NntpAccountData * adata
Definition: mdata.h:47
#define _(a)
Definition: message.h:28
static int nntp_connect_error(struct NntpAccountData *adata)
Signal a failed connection.
Definition: nntp.c:127
#define MUTT_SOCK_LOG_FULL
Definition: mutt_socket.h:31
#define mutt_perror(...)
Definition: logging.h:89
Container for Accounts, Notifications.
Definition: neomutt.h:36
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
#define mutt_socket_send_d(conn, buf, dbg)
Definition: mutt_socket.h:38
char * group
Definition: mdata.h:34
void * mdata
Driver specific data.
Definition: mailbox.h:136
struct NntpAccountData * nntp_select_server(struct Mailbox *m, const char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition: newsrc.c:1017
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
NNTP-specific Mailbox data -.
Definition: mdata.h:32
#define mutt_socket_readln(buf, buflen, conn)
Definition: mutt_socket.h:36
struct Connection * conn
Definition: adata.h:63
static int nntp_query(struct NntpMboxData *mdata, char *line, size_t linelen)
Send data from buffer and receive answer to same buffer.
Definition: nntp.c:691
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:749
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:78
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_active_fetch()

int nntp_active_fetch ( struct NntpAccountData adata,
bool  mark_new 
)

Fetch list of all newsgroups from server.

Parameters
adataNNTP server
mark_newMark the groups as new
Return values
0Success
-1Failure

Definition at line 1963 of file nntp.c.

1964 {
1965  struct NntpMboxData tmp_mdata = { 0 };
1966  char msg[256];
1967  char buf[1024];
1968  unsigned int i;
1969  int rc;
1970 
1971  snprintf(msg, sizeof(msg), _("Loading list of groups from server %s..."),
1972  adata->conn->account.host);
1973  mutt_message(msg);
1974  if (nntp_date(adata, &adata->newgroups_time) < 0)
1975  return -1;
1976 
1977  tmp_mdata.adata = adata;
1978  tmp_mdata.group = NULL;
1979  i = adata->groups_num;
1980  mutt_str_copy(buf, "LIST\r\n", sizeof(buf));
1981  rc = nntp_fetch_lines(&tmp_mdata, buf, sizeof(buf), msg, nntp_add_group, adata);
1982  if (rc)
1983  {
1984  if (rc > 0)
1985  {
1986  mutt_error("LIST: %s", buf);
1987  }
1988  return -1;
1989  }
1990 
1991  if (mark_new)
1992  {
1993  for (; i < adata->groups_num; i++)
1994  {
1995  struct NntpMboxData *mdata = adata->groups_list[i];
1996  mdata->has_new_mail = true;
1997  }
1998  }
1999 
2000  for (i = 0; i < adata->groups_num; i++)
2001  {
2002  struct NntpMboxData *mdata = adata->groups_list[i];
2003 
2004  if (mdata && mdata->deleted && !mdata->newsrc_ent)
2005  {
2006  nntp_delete_group_cache(mdata);
2007  mutt_hash_delete(adata->groups_hash, mdata->group, NULL);
2008  adata->groups_list[i] = NULL;
2009  }
2010  }
2011 
2012  const bool c_nntp_load_description =
2013  cs_subset_bool(NeoMutt->sub, "nntp_load_description");
2014  if (c_nntp_load_description)
2015  rc = get_description(&tmp_mdata, "*", _("Loading descriptions..."));
2016 
2017  nntp_active_save_cache(adata);
2018  if (rc < 0)
2019  return -1;
2020  mutt_clear_error();
2021  return 0;
2022 }
bool has_new_mail
Definition: mdata.h:42
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:40
#define mutt_error(...)
Definition: logging.h:88
struct NntpAccountData * adata
Definition: mdata.h:47
static int nntp_date(struct NntpAccountData *adata, time_t *now)
Get date and time from server.
Definition: nntp.c:1645
#define _(a)
Definition: message.h:28
int nntp_active_save_cache(struct NntpAccountData *adata)
Save list of all newsgroups to cache.
Definition: newsrc.c:650
void nntp_delete_group_cache(struct NntpMboxData *mdata)
Remove hcache and bcache of newsgroup.
Definition: newsrc.c:812
Container for Accounts, Notifications.
Definition: neomutt.h:36
struct HashTable * groups_hash
Definition: adata.h:62
char host[128]
Server to login to.
Definition: connaccount.h:53
time_t newgroups_time
Definition: adata.h:57
char * group
Definition: mdata.h:34
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:112
void * mdata
Driver specific data.
Definition: mailbox.h:136
unsigned int groups_num
Definition: adata.h:59
int nntp_add_group(char *line, void *data)
Parse newsgroup.
Definition: newsrc.c:575
static int get_description(struct NntpMboxData *mdata, const char *wildmat, const char *msg)
Fetch newsgroups descriptions.
Definition: nntp.c:884
struct NewsrcEntry * newsrc_ent
Definition: mdata.h:46
NNTP-specific Mailbox data -.
Definition: mdata.h:32
static int nntp_fetch_lines(struct NntpMboxData *mdata, char *query, size_t qlen, const char *msg, int(*func)(char *, void *), void *data)
Read lines, calling a callback function for each.
Definition: nntp.c:768
struct Connection * conn
Definition: adata.h:63
bool deleted
Definition: mdata.h:44
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:749
void ** groups_list
Definition: adata.h:61
#define mutt_message(...)
Definition: logging.h:87
void mutt_hash_delete(struct HashTable *table, const char *strkey, const void *data)
Remove an element from a Hash Table.
Definition: hash.c:419
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_check_new_groups()

int nntp_check_new_groups ( struct Mailbox m,
struct NntpAccountData adata 
)

Check for new groups/articles in subscribed groups.

Parameters
mMailbox
adataNNTP server
Return values
1New groups found
0No new groups
-1Error

Definition at line 2032 of file nntp.c.

2033 {
2034  struct NntpMboxData tmp_mdata = { 0 };
2035  time_t now;
2036  char buf[1024];
2037  char *msg = _("Checking for new newsgroups...");
2038  unsigned int i;
2039  int rc, update_active = false;
2040 
2041  if (!adata || !adata->newgroups_time)
2042  return -1;
2043 
2044  /* check subscribed newsgroups for new articles */
2045  const bool c_show_new_news = cs_subset_bool(NeoMutt->sub, "show_new_news");
2046  if (c_show_new_news)
2047  {
2048  mutt_message(_("Checking for new messages..."));
2049  for (i = 0; i < adata->groups_num; i++)
2050  {
2051  struct NntpMboxData *mdata = adata->groups_list[i];
2052 
2053  if (mdata && mdata->subscribed)
2054  {
2055  rc = nntp_group_poll(mdata, true);
2056  if (rc < 0)
2057  return -1;
2058  if (rc > 0)
2059  update_active = true;
2060  }
2061  }
2062  }
2063  else if (adata->newgroups_time)
2064  return 0;
2065 
2066  /* get list of new groups */
2067  mutt_message(msg);
2068  if (nntp_date(adata, &now) < 0)
2069  return -1;
2070  tmp_mdata.adata = adata;
2071  if (m && m->mdata)
2072  tmp_mdata.group = ((struct NntpMboxData *) m->mdata)->group;
2073  else
2074  tmp_mdata.group = NULL;
2075  i = adata->groups_num;
2076  struct tm tm = mutt_date_gmtime(adata->newgroups_time);
2077  snprintf(buf, sizeof(buf), "NEWGROUPS %02d%02d%02d %02d%02d%02d GMT\r\n",
2078  tm.tm_year % 100, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
2079  rc = nntp_fetch_lines(&tmp_mdata, buf, sizeof(buf), msg, nntp_add_group, adata);
2080  if (rc)
2081  {
2082  if (rc > 0)
2083  {
2084  mutt_error("NEWGROUPS: %s", buf);
2085  }
2086  return -1;
2087  }
2088 
2089  /* new groups found */
2090  rc = 0;
2091  if (adata->groups_num != i)
2092  {
2093  int groups_num = i;
2094 
2095  adata->newgroups_time = now;
2096  for (; i < adata->groups_num; i++)
2097  {
2098  struct NntpMboxData *mdata = adata->groups_list[i];
2099  mdata->has_new_mail = true;
2100  }
2101 
2102  /* loading descriptions */
2103  const bool c_nntp_load_description =
2104  cs_subset_bool(NeoMutt->sub, "nntp_load_description");
2105  if (c_nntp_load_description)
2106  {
2107  unsigned int count = 0;
2108  struct Progress *progress = progress_new(
2109  _("Loading descriptions..."), MUTT_PROGRESS_READ, adata->groups_num - i);
2110 
2111  for (i = groups_num; i < adata->groups_num; i++)
2112  {
2113  struct NntpMboxData *mdata = adata->groups_list[i];
2114 
2115  if (get_description(mdata, NULL, NULL) < 0)
2116  {
2117  progress_free(&progress);
2118  return -1;
2119  }
2120  progress_update(progress, ++count, -1);
2121  }
2122  progress_free(&progress);
2123  }
2124  update_active = true;
2125  rc = 1;
2126  }
2127  if (update_active)
2128  nntp_active_save_cache(adata);
2129  mutt_clear_error();
2130  return rc;
2131 }
bool has_new_mail
Definition: mdata.h:42
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define mutt_error(...)
Definition: logging.h:88
struct NntpAccountData * adata
Definition: mdata.h:47
static int nntp_date(struct NntpAccountData *adata, time_t *now)
Get date and time from server.
Definition: nntp.c:1645
#define _(a)
Definition: message.h:28
Progress tracks elements, according to $read_inc
Definition: lib.h:46
struct tm mutt_date_gmtime(time_t t)
Converts calendar time to a broken-down time structure expressed in UTC timezone. ...
Definition: date.c:672
int nntp_active_save_cache(struct NntpAccountData *adata)
Save list of all newsgroups to cache.
Definition: newsrc.c:650
Container for Accounts, Notifications.
Definition: neomutt.h:36
A Progress Bar.
Definition: progress.c:47
bool subscribed
Definition: mdata.h:41
time_t newgroups_time
Definition: adata.h:57
char * group
Definition: mdata.h:34
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:112
void * mdata
Driver specific data.
Definition: mailbox.h:136
static int nntp_group_poll(struct NntpMboxData *mdata, bool update_stat)
Check newsgroup for new articles.
Definition: nntp.c:1388
unsigned int groups_num
Definition: adata.h:59
int nntp_add_group(char *line, void *data)
Parse newsgroup.
Definition: newsrc.c:575
static int get_description(struct NntpMboxData *mdata, const char *wildmat, const char *msg)
Fetch newsgroups descriptions.
Definition: nntp.c:884
NNTP-specific Mailbox data -.
Definition: mdata.h:32
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:228
void progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:175
static int nntp_fetch_lines(struct NntpMboxData *mdata, char *query, size_t qlen, const char *msg, int(*func)(char *, void *), void *data)
Read lines, calling a callback function for each.
Definition: nntp.c:768
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:246
void ** groups_list
Definition: adata.h:61
#define mutt_message(...)
Definition: logging.h:87
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_check_msgid()

int nntp_check_msgid ( struct Mailbox m,
const char *  msgid 
)

Fetch article by Message-ID.

Parameters
mMailbox
msgidMessage ID
Return values
0Success
1No such article
-1Error

Definition at line 2141 of file nntp.c.

2142 {
2143  if (!m)
2144  return -1;
2145 
2146  struct NntpMboxData *mdata = m->mdata;
2147  char buf[1024];
2148 
2149  FILE *fp = mutt_file_mkstemp();
2150  if (!fp)
2151  {
2152  mutt_perror(_("Can't create temporary file"));
2153  return -1;
2154  }
2155 
2156  snprintf(buf, sizeof(buf), "HEAD %s\r\n", msgid);
2157  int rc = nntp_fetch_lines(mdata, buf, sizeof(buf), NULL, fetch_tempfile, fp);
2158  if (rc)
2159  {
2160  mutt_file_fclose(&fp);
2161  if (rc < 0)
2162  return -1;
2163  if (mutt_str_startswith(buf, "430"))
2164  return 1;
2165  mutt_error("HEAD: %s", buf);
2166  return -1;
2167  }
2168 
2169  /* parse header */
2170  if (m->msg_count == m->email_max)
2171  mx_alloc_memory(m);
2172  m->emails[m->msg_count] = email_new();
2173  struct Email *e = m->emails[m->msg_count];
2174  e->edata = nntp_edata_new();
2176  e->env = mutt_rfc822_read_header(fp, e, false, false);
2177  mutt_file_fclose(&fp);
2178 
2179  /* get article number */
2180  if (e->env->xref)
2181  nntp_parse_xref(m, e);
2182  else
2183  {
2184  snprintf(buf, sizeof(buf), "STAT %s\r\n", msgid);
2185  if (nntp_query(mdata, buf, sizeof(buf)) < 0)
2186  {
2187  email_free(&e);
2188  return -1;
2189  }
2190  sscanf(buf + 4, ANUM, &nntp_edata_get(e)->article_num);
2191  }
2192 
2193  /* reset flags */
2194  e->read = false;
2195  e->old = false;
2196  e->deleted = false;
2197  e->changed = true;
2198  e->received = e->date_sent;
2199  e->index = m->msg_count++;
2201  return 0;
2202 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
int msg_count
Total number of messages.
Definition: mailbox.h:91
The envelope/body of an email.
Definition: email.h:37
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
static void nntp_parse_xref(struct Mailbox *m, struct Email *e)
Parse cross-reference.
Definition: nntp.c:916
#define mutt_error(...)
Definition: logging.h:88
char * xref
List of cross-references.
Definition: envelope.h:76
static int fetch_tempfile(char *line, void *data)
Write line to temporary file.
Definition: nntp.c:957
void mx_alloc_memory(struct Mailbox *m)
Create storage for the emails.
Definition: mx.c:1212
#define _(a)
Definition: message.h:28
bool changed
Email has been edited.
Definition: email.h:48
Email list was changed.
Definition: mailbox.h:180
#define mutt_perror(...)
Definition: logging.h:89
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
bool read
Email is read.
Definition: email.h:51
bool old
Email is seen, but unread.
Definition: email.h:50
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
struct Envelope * env
Envelope information.
Definition: email.h:90
void * mdata
Driver specific data.
Definition: mailbox.h:136
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:82
#define ANUM
Definition: lib.h:61
void nntp_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free()
Definition: edata.c:38
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
int email_max
Number of pointers in emails.
Definition: mailbox.h:100
void(* edata_free)(void **ptr)
Free the private data attached to the Email.
Definition: email.h:121
struct NntpEmailData * nntp_edata_new(void)
Create a new NntpEmailData for an Email.
Definition: edata.c:48
#define mutt_file_mkstemp()
Definition: file.h:108
struct NntpEmailData * nntp_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:58
NNTP-specific Mailbox data -.
Definition: mdata.h:32
static int nntp_fetch_lines(struct NntpMboxData *mdata, char *query, size_t qlen, const char *msg, int(*func)(char *, void *), void *data)
Read lines, calling a callback function for each.
Definition: nntp.c:768
static int nntp_query(struct NntpMboxData *mdata, char *line, size_t linelen)
Send data from buffer and receive answer to same buffer.
Definition: nntp.c:691
bool deleted
Email is deleted.
Definition: email.h:45
void * edata
Driver-specific data.
Definition: email.h:111
int index
The absolute (unsorted) message number.
Definition: email.h:86
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
parses an RFC822 header
Definition: parse.c:1124
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:208
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:83
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_check_children()

int nntp_check_children ( struct Mailbox m,
const char *  msgid 
)

Fetch children of article with the Message-ID.

Parameters
mMailbox
msgidMessage ID to find
Return values
0Success
-1Failure

Definition at line 2211 of file nntp.c.

2212 {
2213  if (!m)
2214  return -1;
2215 
2216  struct NntpMboxData *mdata = m->mdata;
2217  struct ChildCtx cc;
2218  char buf[256];
2219  int rc;
2220  void *hc = NULL;
2221 
2222  if (!mdata || !mdata->adata)
2223  return -1;
2224  if (mdata->first_message > mdata->last_loaded)
2225  return 0;
2226 
2227  /* init context */
2228  cc.mailbox = m;
2229  cc.num = 0;
2230  cc.max = 10;
2231  cc.child = mutt_mem_malloc(sizeof(anum_t) * cc.max);
2232 
2233  /* fetch numbers of child messages */
2234  snprintf(buf, sizeof(buf), "XPAT References %u-%u *%s*\r\n",
2235  mdata->first_message, mdata->last_loaded, msgid);
2236  rc = nntp_fetch_lines(mdata, buf, sizeof(buf), NULL, fetch_children, &cc);
2237  if (rc)
2238  {
2239  FREE(&cc.child);
2240  if (rc > 0)
2241  {
2242  if (!mutt_str_startswith(buf, "500"))
2243  mutt_error("XPAT: %s", buf);
2244  else
2245  {
2246  mutt_error(_("Unable to find child articles because server does not "
2247  "support XPAT command"));
2248  }
2249  }
2250  return -1;
2251  }
2252 
2253  /* fetch all found messages */
2254  bool verbose = m->verbose;
2255  m->verbose = false;
2256 #ifdef USE_HCACHE
2257  hc = nntp_hcache_open(mdata);
2258 #endif
2259  int old_msg_count = m->msg_count;
2260  for (int i = 0; i < cc.num; i++)
2261  {
2262  rc = nntp_fetch_headers(m, hc, cc.child[i], cc.child[i], true);
2263  if (rc < 0)
2264  break;
2265  }
2266  if (m->msg_count > old_msg_count)
2268 
2269 #ifdef USE_HCACHE
2270  mutt_hcache_close(hc);
2271 #endif
2272  m->verbose = verbose;
2273  FREE(&cc.child);
2274  return (rc < 0) ? -1 : 0;
2275 }
int msg_count
Total number of messages.
Definition: mailbox.h:91
#define mutt_error(...)
Definition: logging.h:88
static int nntp_fetch_headers(struct Mailbox *m, void *hc, anum_t first, anum_t last, bool restore)
Fetch headers.
Definition: nntp.c:1154
struct NntpAccountData * adata
Definition: mdata.h:47
#define _(a)
Definition: message.h:28
Keep track of the children of an article.
Definition: nntp.c:106
Email list was changed.
Definition: mailbox.h:180
anum_t last_loaded
Definition: mdata.h:38
void * mdata
Driver specific data.
Definition: mailbox.h:136
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
struct HeaderCache * nntp_hcache_open(struct NntpMboxData *mdata)
Open newsgroup hcache.
Definition: newsrc.c:709
bool verbose
Display status messages?
Definition: mailbox.h:118
struct Mailbox * mailbox
Definition: nntp.c:108
NNTP-specific Mailbox data -.
Definition: mdata.h:32
static int nntp_fetch_lines(struct NntpMboxData *mdata, char *query, size_t qlen, const char *msg, int(*func)(char *, void *), void *data)
Read lines, calling a callback function for each.
Definition: nntp.c:768
static int fetch_children(char *line, void *data)
Parse XPAT line.
Definition: nntp.c:1682
void mutt_hcache_close(struct HeaderCache *hc)
Multiplexor for StoreOps::close.
Definition: hcache.c:435
anum_t first_message
Definition: mdata.h:36
#define FREE(x)
Definition: memory.h:40
#define anum_t
Definition: lib.h:60
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:208
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_compare_order()

int nntp_compare_order ( const struct Email a,
const struct Email b,
bool  reverse 
)

Sort to mailbox order - Implements sort_mail_t.

Definition at line 2280 of file nntp.c.

2281 {
2282  anum_t na = nntp_edata_get((struct Email *) a)->article_num;
2283  anum_t nb = nntp_edata_get((struct Email *) b)->article_num;
2284  int result = (na == nb) ? 0 : (na > nb) ? 1 : -1;
2285  return reverse ? -result : result;
2286 }
The envelope/body of an email.
Definition: email.h:37
anum_t article_num
Definition: edata.h:36
struct NntpEmailData * nntp_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:58
#define anum_t
Definition: lib.h:60
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ CurrentNewsSrv

struct NntpAccountData* CurrentNewsSrv

Current NNTP news server.

Definition at line 78 of file nntp.c.

◆ OverviewFmt

const char* OverviewFmt
Initial value:
= "Subject:\0"
"From:\0"
"Date:\0"
"Message-ID:\0"
"References:\0"
"Content-Length:\0"
"Lines:\0"
"\0"

Definition at line 80 of file nntp.c.