NeoMutt  2025-12-11-911-gd8d604
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
private.h File Reference

Shared constants/structs that are private to IMAP. More...

#include "config.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "config/lib.h"
+ Include dependency graph for private.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ImapList
 Items in an IMAP browser. More...
 
struct  ImapCommand
 IMAP command structure. More...
 
struct  SeqsetIterator
 UID Sequence Set Iterator. More...
 

Macros

#define IMAP_PORT   143
 Default port for IMAP.
 
#define IMAP_SSL_PORT   993
 Port for IMAP over SSL/TLS.
 
#define IMAP_LOG_CMD   2
 Log commands only.
 
#define IMAP_LOG_LTRL   3
 Log literal values.
 
#define IMAP_LOG_PASS   5
 Log passwords (dangerous!)
 
#define IMAP_RES_NO   -2
 <tag> NO ...
 
#define IMAP_RES_BAD   -1
 <tag> BAD ...
 
#define IMAP_RES_OK   0
 <tag> OK ...
 
#define IMAP_RES_CONTINUE   1
 * ...
 
#define IMAP_RES_RESPOND   2
 +
 
#define IMAP_RES_NEW   3
 ImapCommand.state additions.
 
#define SEQ_LEN   16
 Length of IMAP sequence buffer.
 
#define IMAP_DATELEN   27
 Length of IMAP date string "DD-MMM-YYYY HH:MM:SS +ZZzz" plus NUL.
 
#define IMAP_CAP_ALL   ((1 << 21) - 1)
 

Typedefs

typedef uint8_t ImapOpenFlags
 
typedef uint8_t ImapCmdFlags
 
typedef uint32_t ImapCapFlags
 

Enumerations

enum  ImapOpenFlag {
  IMAP_OPEN_NONE = 0 , IMAP_REOPEN_ALLOW = 1U << 0 , IMAP_EXPUNGE_EXPECTED = 1U << 1 , IMAP_EXPUNGE_PENDING = 1U << 2 ,
  IMAP_NEWMAIL_PENDING = 1U << 3 , IMAP_FLAGS_PENDING = 1U << 4 , IMAP_SYNC_IN_PROGRESS = 1U << 5
}
 State flags for IMAP mailbox reopen and sync handling. More...
 
enum  ImapCmdFlag {
  IMAP_CMD_NONE = 0 , IMAP_CMD_PASS = 1U << 0 , IMAP_CMD_QUEUE = 1U << 1 , IMAP_CMD_POLL = 1U << 2 ,
  IMAP_CMD_SINGLE = 1U << 3
}
 Flags for imap_exec(), e.g. More...
 
enum  ImapExecResult { IMAP_EXEC_SUCCESS = 0 , IMAP_EXEC_ERROR , IMAP_EXEC_FATAL }
 Imap_exec return code. More...
 
enum  ImapFlags { IMAP_FATAL = 1 , IMAP_BYE }
 IMAP server responses. More...
 
enum  ImapState {
  IMAP_DISCONNECTED = 0 , IMAP_CONNECTED , IMAP_AUTHENTICATED , IMAP_SELECTED ,
  IMAP_IDLE
}
 IMAP connection state. More...
 
enum  ImapCapFlag {
  IMAP_CAP_NONE = 0 , IMAP_CAP_IMAP4 = 1U << 0 , IMAP_CAP_IMAP4REV1 = 1U << 1 , IMAP_CAP_STATUS = 1U << 2 ,
  IMAP_CAP_ACL = 1U << 3 , IMAP_CAP_NAMESPACE = 1U << 4 , IMAP_CAP_AUTH_CRAM_MD5 = 1U << 5 , IMAP_CAP_AUTH_GSSAPI = 1U << 6 ,
  IMAP_CAP_AUTH_ANONYMOUS = 1U << 7 , IMAP_CAP_AUTH_OAUTHBEARER = 1U << 8 , IMAP_CAP_AUTH_XOAUTH2 = 1U << 9 , IMAP_CAP_STARTTLS = 1U << 10 ,
  IMAP_CAP_LOGINDISABLED = 1U << 11 , IMAP_CAP_IDLE = 1U << 12 , IMAP_CAP_SASL_IR = 1U << 13 , IMAP_CAP_ENABLE = 1U << 14 ,
  IMAP_CAP_CONDSTORE = 1U << 15 , IMAP_CAP_QRESYNC = 1U << 16 , IMAP_CAP_LIST_EXTENDED = 1U << 17 , IMAP_CAP_COMPRESS = 1U << 18 ,
  IMAP_CAP_X_GM_EXT_1 = 1U << 19 , IMAP_CAP_ID = 1U << 20
}
 Capabilities we are interested in. More...
 

Functions

int imap_create_mailbox (struct ImapAccountData *adata, const char *mailbox)
 Create a new mailbox.
 
int imap_rename_mailbox (struct ImapAccountData *adata, char *oldname, const char *newname)
 Rename a mailbox.
 
int imap_open_connection (struct ImapAccountData *adata)
 Open an IMAP connection.
 
void imap_close_connection (struct ImapAccountData *adata)
 Close an IMAP connection.
 
int imap_read_literal (FILE *fp, struct ImapAccountData *adata, unsigned long bytes, struct Progress *progress)
 Read bytes bytes from server into file.
 
void imap_expunge_mailbox (struct Mailbox *m, bool resort)
 Purge messages from the server.
 
int imap_login (struct ImapAccountData *adata)
 Open an IMAP connection.
 
int imap_sync_message_for_copy (struct Mailbox *m, struct Email *e, struct Buffer *cmd, enum QuadOption *err_continue)
 Update server to reflect the flags of a single message.
 
bool imap_has_flag (struct ListHead *flag_list, const char *flag)
 Does the flag exist in the list.
 
int imap_adata_find (const char *path, struct ImapAccountData **adata, struct ImapMboxData **mdata)
 Find the Account data for this path.
 
int imap_reopen_mailbox (struct ImapAccountData *adata)
 Re-SELECT the current mailbox after reconnecting.
 
int imap_authenticate (struct ImapAccountData *adata)
 Authenticate to an IMAP server.
 
int imap_cmd_start (struct ImapAccountData *adata, const char *cmdstr)
 Given an IMAP command, send it to the server.
 
int imap_cmd_step (struct ImapAccountData *adata)
 Reads server responses from an IMAP command.
 
void imap_cmd_finish (struct ImapAccountData *adata)
 Attempt to perform cleanup.
 
bool imap_code (const char *s)
 Was the command successful.
 
const char * imap_cmd_trailer (struct ImapAccountData *adata)
 Extra information after tagged command response if any.
 
int imap_exec (struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
 Execute a command and wait for the response from the server.
 
int imap_cmd_idle (struct ImapAccountData *adata)
 Enter the IDLE state.
 
int imap_read_headers (struct Mailbox *m, unsigned int msn_begin, unsigned int msn_end, bool initial_download)
 Read headers from the server.
 
char * imap_set_flags (struct Mailbox *m, struct Email *e, char *s, bool *server_changes)
 Fill the message header according to the server flags.
 
int imap_cache_del (struct Mailbox *m, struct Email *e)
 Delete an email from the body cache.
 
int imap_cache_clean (struct Mailbox *m)
 Delete all the entries in the message cache.
 
int imap_append_message (struct Mailbox *m, struct Message *msg)
 Write an email back to the server.
 
bool imap_msg_open (struct Mailbox *m, struct Message *msg, struct Email *e)
 Open an email message in a Mailbox - Implements MxOps::msg_open() -.
 
int imap_msg_close (struct Mailbox *m, struct Message *msg)
 Close an email - Implements MxOps::msg_close() -.
 
int imap_msg_commit (struct Mailbox *m, struct Message *msg)
 Save changes to an email - Implements MxOps::msg_commit() -.
 
int imap_msg_save_hcache (struct Mailbox *m, struct Email *e)
 Save message to the header cache - Implements MxOps::msg_save_hcache() -.
 
void imap_hcache_open (struct ImapAccountData *adata, struct ImapMboxData *mdata, bool create)
 Open a header cache.
 
void imap_hcache_close (struct ImapMboxData *mdata)
 Close the header cache.
 
struct Emailimap_hcache_get (struct ImapMboxData *mdata, unsigned int uid)
 Get a header cache entry by its UID.
 
int imap_hcache_put (struct ImapMboxData *mdata, struct Email *e)
 Add an entry to the header cache.
 
int imap_hcache_del (struct ImapMboxData *mdata, unsigned int uid)
 Delete an item from the header cache.
 
int imap_hcache_store_uid_seqset (struct ImapMboxData *mdata)
 Store a UID Sequence Set in the header cache.
 
int imap_hcache_clear_uid_seqset (struct ImapMboxData *mdata)
 Delete a UID Sequence Set from the header cache.
 
char * imap_hcache_get_uid_seqset (struct ImapMboxData *mdata)
 Get a UID Sequence Set from the header cache.
 
enum QuadOption imap_continue (const char *msg, const char *resp)
 Display a message and ask the user if they want to go on.
 
void imap_error (const char *where, const char *msg)
 Show an error and abort.
 
void imap_mdata_cache_reset (struct ImapMboxData *mdata)
 Release and clear cache data of ImapMboxData structure.
 
char * imap_fix_path (const char *mailbox, char *path, size_t plen)
 Fix up the imap path.
 
char * imap_fix_path_with_delim (char delim, const char *mailbox, char *path, size_t plen)
 Fix up the imap path.
 
void imap_cachepath (char delim, const char *mailbox, struct Buffer *dest)
 Generate a cache path for a mailbox.
 
int imap_get_literal_count (char *buf, unsigned int *bytes)
 Write number of bytes in an IMAP literal into bytes.
 
char * imap_get_qualifier (char *buf)
 Get the qualifier from a tagged response.
 
char * imap_next_word (char *s)
 Find where the next IMAP word begins.
 
void imap_qualify_path (char *buf, size_t buflen, struct ConnAccount *conn_account, char *path)
 Make an absolute IMAP folder target.
 
void imap_buf_qualify_path (struct Buffer *buf, struct ConnAccount *conn_account, char *path)
 Make an absolute IMAP folder target to a buffer.
 
void imap_quote_string (char *dest, size_t dlen, const char *src, bool quote_backtick)
 Quote string according to IMAP rules.
 
void imap_unquote_string (char *s)
 Equally stupid unquoting routine.
 
void imap_munge_mbox_name (bool unicode, char *dest, size_t dlen, const char *src)
 Quote awkward characters in a mailbox name.
 
void imap_unmunge_mbox_name (bool unicode, char *s)
 Remove quoting from a mailbox name.
 
struct SeqsetIteratormutt_seqset_iterator_new (const char *seqset)
 Create a new Sequence Set Iterator.
 
int mutt_seqset_iterator_next (struct SeqsetIterator *iter, unsigned int *next)
 Get the next UID from a Sequence Set.
 
void mutt_seqset_iterator_free (struct SeqsetIterator **ptr)
 Free a Sequence Set Iterator.
 
bool imap_account_match (const struct ConnAccount *a1, const struct ConnAccount *a2)
 Compare two Accounts.
 
void imap_get_parent (const char *mbox, char delim, char *buf, size_t buflen)
 Get an IMAP folder's parent.
 
bool mutt_account_match (const struct ConnAccount *a1, const struct ConnAccount *a2)
 
void imap_utf_encode (bool unicode, char **s)
 Encode email from local charset to UTF-8.
 
void imap_utf_decode (bool unicode, char **s)
 Decode email from UTF-8 to local charset.
 
void imap_allow_reopen (struct Mailbox *m)
 Allow re-opening a folder upon expunge.
 
void imap_disallow_reopen (struct Mailbox *m)
 Disallow re-opening a folder upon expunge.
 
void cmd_parse_search (struct ImapAccountData *adata, const char *s)
 Store SEARCH response for later use.
 

Detailed Description

Shared constants/structs that are private to IMAP.

Authors
  • Pietro Cerutti
  • Richard Russon
  • Mehdi Abaakouk

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 private.h.

Macro Definition Documentation

◆ IMAP_PORT

#define IMAP_PORT   143

Default port for IMAP.

Definition at line 44 of file private.h.

◆ IMAP_SSL_PORT

#define IMAP_SSL_PORT   993

Port for IMAP over SSL/TLS.

Definition at line 45 of file private.h.

◆ IMAP_LOG_CMD

#define IMAP_LOG_CMD   2

Log commands only.

Definition at line 47 of file private.h.

◆ IMAP_LOG_LTRL

#define IMAP_LOG_LTRL   3

Log literal values.

Definition at line 48 of file private.h.

◆ IMAP_LOG_PASS

#define IMAP_LOG_PASS   5

Log passwords (dangerous!)

Definition at line 49 of file private.h.

◆ IMAP_RES_NO

#define IMAP_RES_NO   -2

<tag> NO ...

Definition at line 52 of file private.h.

◆ IMAP_RES_BAD

#define IMAP_RES_BAD   -1

<tag> BAD ...

Definition at line 53 of file private.h.

◆ IMAP_RES_OK

#define IMAP_RES_OK   0

<tag> OK ...

Definition at line 54 of file private.h.

◆ IMAP_RES_CONTINUE

#define IMAP_RES_CONTINUE   1

* ...

Definition at line 55 of file private.h.

◆ IMAP_RES_RESPOND

#define IMAP_RES_RESPOND   2

+

Definition at line 56 of file private.h.

◆ IMAP_RES_NEW

#define IMAP_RES_NEW   3

ImapCommand.state additions.

Definition at line 57 of file private.h.

◆ SEQ_LEN

#define SEQ_LEN   16

Length of IMAP sequence buffer.

Definition at line 60 of file private.h.

◆ IMAP_DATELEN

#define IMAP_DATELEN   27

Length of IMAP date string "DD-MMM-YYYY HH:MM:SS +ZZzz" plus NUL.

Definition at line 101 of file private.h.

◆ IMAP_CAP_ALL

#define IMAP_CAP_ALL   ((1 << 21) - 1)

Definition at line 159 of file private.h.

Typedef Documentation

◆ ImapOpenFlags

typedef uint8_t ImapOpenFlags

Definition at line 75 of file private.h.

◆ ImapCmdFlags

typedef uint8_t ImapCmdFlags

Definition at line 88 of file private.h.

◆ ImapCapFlags

typedef uint32_t ImapCapFlags

Definition at line 157 of file private.h.

Enumeration Type Documentation

◆ ImapOpenFlag

State flags for IMAP mailbox reopen and sync handling.

Enumerator
IMAP_OPEN_NONE 

No flags are set.

IMAP_REOPEN_ALLOW 

Allow re-opening a folder upon expunge.

IMAP_EXPUNGE_EXPECTED 

Messages will be expunged from the server.

IMAP_EXPUNGE_PENDING 

Messages on the server have been expunged.

IMAP_NEWMAIL_PENDING 

New mail is waiting on the server.

IMAP_FLAGS_PENDING 

Flags have changed on the server.

IMAP_SYNC_IN_PROGRESS 

Sync is in progress, block expunge/newmail processing.

Definition at line 65 of file private.h.

66{
67 IMAP_OPEN_NONE = 0,
68 IMAP_REOPEN_ALLOW = 1U << 0,
69 IMAP_EXPUNGE_EXPECTED = 1U << 1,
70 IMAP_EXPUNGE_PENDING = 1U << 2,
71 IMAP_NEWMAIL_PENDING = 1U << 3,
72 IMAP_FLAGS_PENDING = 1U << 4,
73 IMAP_SYNC_IN_PROGRESS = 1U << 5,
74};
@ IMAP_EXPUNGE_PENDING
Messages on the server have been expunged.
Definition private.h:70
@ IMAP_NEWMAIL_PENDING
New mail is waiting on the server.
Definition private.h:71
@ IMAP_SYNC_IN_PROGRESS
Sync is in progress, block expunge/newmail processing.
Definition private.h:73
@ IMAP_EXPUNGE_EXPECTED
Messages will be expunged from the server.
Definition private.h:69
@ IMAP_OPEN_NONE
No flags are set.
Definition private.h:67
@ IMAP_FLAGS_PENDING
Flags have changed on the server.
Definition private.h:72
@ IMAP_REOPEN_ALLOW
Allow re-opening a folder upon expunge.
Definition private.h:68

◆ ImapCmdFlag

Flags for imap_exec(), e.g.

IMAP_CMD_PASS

Enumerator
IMAP_CMD_NONE 

No flags are set.

IMAP_CMD_PASS 

Command contains a password. Suppress logging.

IMAP_CMD_QUEUE 

Queue a command, do not execute.

IMAP_CMD_POLL 

Poll the tcp connection before running the imap command.

IMAP_CMD_SINGLE 

Run a single command.

Definition at line 80 of file private.h.

81{
82 IMAP_CMD_NONE = 0,
83 IMAP_CMD_PASS = 1U << 0,
84 IMAP_CMD_QUEUE = 1U << 1,
85 IMAP_CMD_POLL = 1U << 2,
86 IMAP_CMD_SINGLE = 1U << 3,
87};
@ IMAP_CMD_POLL
Poll the tcp connection before running the imap command.
Definition private.h:85
@ IMAP_CMD_SINGLE
Run a single command.
Definition private.h:86
@ IMAP_CMD_NONE
No flags are set.
Definition private.h:82
@ IMAP_CMD_QUEUE
Queue a command, do not execute.
Definition private.h:84
@ IMAP_CMD_PASS
Command contains a password. Suppress logging.
Definition private.h:83

◆ ImapExecResult

Imap_exec return code.

Enumerator
IMAP_EXEC_SUCCESS 

Imap command executed or queued successfully.

IMAP_EXEC_ERROR 

Imap command failure.

IMAP_EXEC_FATAL 

Imap connection failure.

Definition at line 93 of file private.h.

94{
98};
@ IMAP_EXEC_SUCCESS
Imap command executed or queued successfully.
Definition private.h:95
@ IMAP_EXEC_ERROR
Imap command failure.
Definition private.h:96
@ IMAP_EXEC_FATAL
Imap connection failure.
Definition private.h:97

◆ ImapFlags

enum ImapFlags

IMAP server responses.

Enumerator
IMAP_FATAL 

Unrecoverable error occurred.

IMAP_BYE 

Logged out from server.

Definition at line 106 of file private.h.

107{
108 IMAP_FATAL = 1,
109 IMAP_BYE,
110};
@ IMAP_BYE
Logged out from server.
Definition private.h:109
@ IMAP_FATAL
Unrecoverable error occurred.
Definition private.h:108

◆ ImapState

enum ImapState

IMAP connection state.

Enumerator
IMAP_DISCONNECTED 

Disconnected from server.

IMAP_CONNECTED 

Connected to server.

IMAP_AUTHENTICATED 

Connection is authenticated.

IMAP_SELECTED 

Mailbox is selected.

IMAP_IDLE 

Connection is idle.

Definition at line 115 of file private.h.

116{
117 /* States */
122
123 /* and pseudo-states */
124 IMAP_IDLE,
125};
@ IMAP_DISCONNECTED
Disconnected from server.
Definition private.h:118
@ IMAP_IDLE
Connection is idle.
Definition private.h:124
@ IMAP_AUTHENTICATED
Connection is authenticated.
Definition private.h:120
@ IMAP_SELECTED
Mailbox is selected.
Definition private.h:121
@ IMAP_CONNECTED
Connected to server.
Definition private.h:119

◆ ImapCapFlag

Capabilities we are interested in.

Note
This must be kept in the same order as Capabilities.
Enumerator
IMAP_CAP_NONE 

No flags are set.

IMAP_CAP_IMAP4 

Server supports IMAP4.

IMAP_CAP_IMAP4REV1 

Server supports IMAP4rev1.

IMAP_CAP_STATUS 

Server supports STATUS command.

IMAP_CAP_ACL 

RFC2086: IMAP4 ACL extension.

IMAP_CAP_NAMESPACE 

RFC2342: IMAP4 Namespace.

IMAP_CAP_AUTH_CRAM_MD5 

RFC2195: CRAM-MD5 authentication.

IMAP_CAP_AUTH_GSSAPI 

RFC1731: GSSAPI authentication.

IMAP_CAP_AUTH_ANONYMOUS 

AUTH=ANONYMOUS.

IMAP_CAP_AUTH_OAUTHBEARER 

RFC7628: AUTH=OAUTHBEARER.

IMAP_CAP_AUTH_XOAUTH2 

AUTH=XOAUTH2, deprecated but used by OWA.

IMAP_CAP_STARTTLS 

RFC2595: STARTTLS.

IMAP_CAP_LOGINDISABLED 

RFC2595: LOGINDISABLED.

IMAP_CAP_IDLE 

RFC2177: IDLE.

IMAP_CAP_SASL_IR 

SASL initial response draft.

IMAP_CAP_ENABLE 

RFC5161.

IMAP_CAP_CONDSTORE 

RFC7162.

IMAP_CAP_QRESYNC 

RFC7162.

IMAP_CAP_LIST_EXTENDED 

RFC5258: IMAP4 LIST Command Extensions.

IMAP_CAP_COMPRESS 

RFC4978: COMPRESS=DEFLATE.

IMAP_CAP_X_GM_EXT_1 

https://developers.google.com/gmail/imap/imap-extensions

IMAP_CAP_ID 

RFC2971: IMAP4 ID extension.

Definition at line 132 of file private.h.

133{
134 IMAP_CAP_NONE = 0,
135 IMAP_CAP_IMAP4 = 1U << 0,
136 IMAP_CAP_IMAP4REV1 = 1U << 1,
137 IMAP_CAP_STATUS = 1U << 2,
138 IMAP_CAP_ACL = 1U << 3,
139 IMAP_CAP_NAMESPACE = 1U << 4,
140 IMAP_CAP_AUTH_CRAM_MD5 = 1U << 5,
141 IMAP_CAP_AUTH_GSSAPI = 1U << 6,
142 IMAP_CAP_AUTH_ANONYMOUS = 1U << 7,
143 IMAP_CAP_AUTH_OAUTHBEARER = 1U << 8,
144 IMAP_CAP_AUTH_XOAUTH2 = 1U << 9,
145 IMAP_CAP_STARTTLS = 1U << 10,
146 IMAP_CAP_LOGINDISABLED = 1U << 11,
147 IMAP_CAP_IDLE = 1U << 12,
148 IMAP_CAP_SASL_IR = 1U << 13,
149 IMAP_CAP_ENABLE = 1U << 14,
150 IMAP_CAP_CONDSTORE = 1U << 15,
151 IMAP_CAP_QRESYNC = 1U << 16,
152 IMAP_CAP_LIST_EXTENDED = 1U << 17,
153 IMAP_CAP_COMPRESS = 1U << 18,
154 IMAP_CAP_X_GM_EXT_1 = 1U << 19,
155 IMAP_CAP_ID = 1U << 20,
156};
@ IMAP_CAP_CONDSTORE
RFC7162.
Definition private.h:150
@ IMAP_CAP_QRESYNC
RFC7162.
Definition private.h:151
@ IMAP_CAP_NONE
No flags are set.
Definition private.h:134
@ IMAP_CAP_STARTTLS
RFC2595: STARTTLS.
Definition private.h:145
@ IMAP_CAP_AUTH_CRAM_MD5
RFC2195: CRAM-MD5 authentication.
Definition private.h:140
@ IMAP_CAP_AUTH_ANONYMOUS
AUTH=ANONYMOUS.
Definition private.h:142
@ IMAP_CAP_X_GM_EXT_1
https://developers.google.com/gmail/imap/imap-extensions
Definition private.h:154
@ IMAP_CAP_COMPRESS
RFC4978: COMPRESS=DEFLATE.
Definition private.h:153
@ IMAP_CAP_ENABLE
RFC5161.
Definition private.h:149
@ IMAP_CAP_IMAP4REV1
Server supports IMAP4rev1.
Definition private.h:136
@ IMAP_CAP_IMAP4
Server supports IMAP4.
Definition private.h:135
@ IMAP_CAP_NAMESPACE
RFC2342: IMAP4 Namespace.
Definition private.h:139
@ IMAP_CAP_LOGINDISABLED
RFC2595: LOGINDISABLED.
Definition private.h:146
@ IMAP_CAP_ID
RFC2971: IMAP4 ID extension.
Definition private.h:155
@ IMAP_CAP_AUTH_XOAUTH2
AUTH=XOAUTH2, deprecated but used by OWA.
Definition private.h:144
@ IMAP_CAP_AUTH_GSSAPI
RFC1731: GSSAPI authentication.
Definition private.h:141
@ IMAP_CAP_ACL
RFC2086: IMAP4 ACL extension.
Definition private.h:138
@ IMAP_CAP_STATUS
Server supports STATUS command.
Definition private.h:137
@ IMAP_CAP_AUTH_OAUTHBEARER
RFC7628: AUTH=OAUTHBEARER.
Definition private.h:143
@ IMAP_CAP_SASL_IR
SASL initial response draft.
Definition private.h:148
@ IMAP_CAP_LIST_EXTENDED
RFC5258: IMAP4 LIST Command Extensions.
Definition private.h:152
@ IMAP_CAP_IDLE
RFC2177: IDLE.
Definition private.h:147

Function Documentation

◆ imap_create_mailbox()

int imap_create_mailbox ( struct ImapAccountData * adata,
const char * mailbox )

Create a new mailbox.

Parameters
adataImap Account data
mailboxMailbox to create
Return values
0Success
-1Failure

Definition at line 542 of file imap.c.

543{
544 char buf[2048] = { 0 };
545 char mbox[1024] = { 0 };
546
547 imap_munge_mbox_name(adata->unicode, mbox, sizeof(mbox), mailbox);
548 snprintf(buf, sizeof(buf), "CREATE %s", mbox);
549
550 if (imap_exec(adata, buf, IMAP_CMD_NONE) != IMAP_EXEC_SUCCESS)
551 {
552 mutt_error(_("CREATE failed: %s"), imap_cmd_trailer(adata));
553 return -1;
554 }
555
556 return 0;
557}
#define mutt_error(...)
Definition logging2.h:94
const char * imap_cmd_trailer(struct ImapAccountData *adata)
Extra information after tagged command response if any.
Definition command.c:1383
int imap_exec(struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
Execute a command and wait for the response from the server.
Definition command.c:1420
void imap_munge_mbox_name(bool unicode, char *dest, size_t dlen, const char *src)
Quote awkward characters in a mailbox name.
Definition util.c:971
#define _(a)
Definition message.h:28
bool unicode
If true, we can send UTF-8, and the server will use UTF8 rather than mUTF7.
Definition adata.h:64
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_rename_mailbox()

int imap_rename_mailbox ( struct ImapAccountData * adata,
char * oldname,
const char * newname )

Rename a mailbox.

Parameters
adataImap Account data
oldnameExisting mailbox
newnameNew name for mailbox
Return values
0Success
-1Failure

Definition at line 584 of file imap.c.

585{
586 char oldmbox[1024] = { 0 };
587 char newmbox[1024] = { 0 };
588 int rc = 0;
589
590 imap_munge_mbox_name(adata->unicode, oldmbox, sizeof(oldmbox), oldname);
591 imap_munge_mbox_name(adata->unicode, newmbox, sizeof(newmbox), newname);
592
593 struct Buffer *buf = buf_pool_get();
594 buf_printf(buf, "RENAME %s %s", oldmbox, newmbox);
595
597 rc = -1;
598
599 buf_pool_release(&buf);
600
601 return rc;
602}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
String manipulation buffer.
Definition buffer.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_open_connection()

int imap_open_connection ( struct ImapAccountData * adata)

Open an IMAP connection.

Parameters
adataImap Account data
Return values
0Success
-1Failure

Definition at line 921 of file imap.c.

922{
923 if (mutt_socket_open(adata->conn) < 0)
924 return -1;
925
926 adata->state = IMAP_CONNECTED;
927
928 if (imap_cmd_step(adata) != IMAP_RES_OK)
929 {
931 return -1;
932 }
933
934 if (mutt_istr_startswith(adata->buf, "* OK"))
935 {
936 if (!mutt_istr_startswith(adata->buf, "* OK [CAPABILITY") && check_capabilities(adata))
937 {
938 goto bail;
939 }
940#ifdef USE_SSL
941 /* Attempt STARTTLS if available and desired. */
942 const bool c_ssl_force_tls = cs_subset_bool(NeoMutt->sub, "ssl_force_tls");
943 if ((adata->conn->ssf == 0) &&
944 (c_ssl_force_tls || (adata->capabilities & IMAP_CAP_STARTTLS)))
945 {
946 enum QuadOption ans;
947
948 if (c_ssl_force_tls)
949 {
950 ans = MUTT_YES;
951 }
952 else if ((ans = query_quadoption(_("Secure connection with TLS?"),
953 NeoMutt->sub, "ssl_starttls")) == MUTT_ABORT)
954 {
955 goto bail;
956 }
957 if (ans == MUTT_YES)
958 {
959 enum ImapExecResult rc = imap_exec(adata, "STARTTLS", IMAP_CMD_SINGLE);
960 // Clear any data after the STARTTLS acknowledgement
961 mutt_socket_empty(adata->conn);
962
963 if (rc == IMAP_EXEC_FATAL)
964 goto bail;
965 if (rc != IMAP_EXEC_ERROR)
966 {
967 if (mutt_ssl_starttls(adata->conn) == 0)
968 {
969 /* RFC2595 demands we recheck CAPABILITY after TLS completes. */
970 if (imap_exec(adata, "CAPABILITY", IMAP_CMD_NONE) != IMAP_EXEC_SUCCESS)
971 goto bail;
972 }
973 else
974 {
975 mutt_error(_("Could not negotiate TLS connection"));
976 goto bail;
977 }
978 }
979 }
980 }
981
982 if (c_ssl_force_tls && (adata->conn->ssf == 0))
983 {
984 mutt_error(_("Encrypted connection unavailable"));
985 goto bail;
986 }
987#endif
988 }
989 else if (mutt_istr_startswith(adata->buf, "* PREAUTH"))
990 {
991#ifdef USE_SSL
992 /* Unless using a secure $tunnel, an unencrypted PREAUTH response may be a
993 * MITM attack. The only way to stop "STARTTLS" MITM attacks is via
994 * $ssl_force_tls: an attacker can easily spoof "* OK" and strip the
995 * STARTTLS capability. So consult $ssl_force_tls, not $ssl_starttls, to
996 * decide whether to abort. Note that if using $tunnel and
997 * $tunnel_is_secure, adata->conn->ssf will be set to 1. */
998 const bool c_ssl_force_tls = cs_subset_bool(NeoMutt->sub, "ssl_force_tls");
999 if ((adata->conn->ssf == 0) && c_ssl_force_tls)
1000 {
1001 mutt_error(_("Encrypted connection unavailable"));
1002 goto bail;
1003 }
1004#endif
1005
1006 adata->state = IMAP_AUTHENTICATED;
1007 if (check_capabilities(adata) != 0)
1008 goto bail;
1009 FREE(&adata->capstr);
1010 }
1011 else
1012 {
1013 imap_error("imap_open_connection()", adata->buf);
1014 goto bail;
1015 }
1016
1017 return 0;
1018
1019bail:
1020 imap_close_connection(adata);
1021 FREE(&adata->capstr);
1022 return -1;
1023}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
int mutt_ssl_starttls(struct Connection *conn)
Negotiate TLS over an already opened connection.
Definition gnutls.c:1172
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition command.c:1230
#define IMAP_RES_OK
<tag> OK ...
Definition private.h:54
ImapExecResult
Imap_exec return code.
Definition private.h:94
void imap_error(const char *where, const char *msg)
Show an error and abort.
Definition util.c:665
void imap_close_connection(struct ImapAccountData *adata)
Close an IMAP connection.
Definition imap.c:1029
static int check_capabilities(struct ImapAccountData *adata)
Make sure we can log in to this server.
Definition imap.c:207
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition string.c:246
QuadOption
Possible values for a quad-option.
Definition quad.h:36
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition quad.h:37
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition question.c:384
void mutt_socket_empty(struct Connection *conn)
Clear out any queued data.
Definition socket.c:306
int mutt_socket_open(struct Connection *conn)
Simple wrapper.
Definition socket.c:76
unsigned int ssf
Security strength factor, in bits (see notes)
Definition connection.h:50
ImapCapFlags capabilities
Capability flags.
Definition adata.h:56
unsigned char state
ImapState, e.g. IMAP_AUTHENTICATED.
Definition adata.h:45
char * capstr
Capability string from the server.
Definition adata.h:55
char * buf
Command buffer.
Definition adata.h:61
struct Connection * conn
Connection to IMAP server.
Definition adata.h:41
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_close_connection()

void imap_close_connection ( struct ImapAccountData * adata)

Close an IMAP connection.

Parameters
adataImap Account data

Definition at line 1029 of file imap.c.

1030{
1031 if (adata->state != IMAP_DISCONNECTED)
1032 {
1033 mutt_socket_close(adata->conn);
1034 adata->state = IMAP_DISCONNECTED;
1035 }
1036 adata->seqno = 0;
1037 adata->nextcmd = 0;
1038 adata->lastcmd = 0;
1039 adata->status = 0;
1040 memset(adata->cmds, 0, sizeof(struct ImapCommand) * adata->cmdslots);
1041}
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition socket.c:100
int lastcmd
Last command in the queue.
Definition adata.h:76
int nextcmd
Next command to be sent.
Definition adata.h:75
struct ImapCommand * cmds
Queue of commands for the server.
Definition adata.h:73
unsigned char status
ImapFlags, e.g. IMAP_FATAL.
Definition adata.h:46
int cmdslots
Size of the command queue.
Definition adata.h:74
unsigned int seqno
tag sequence number, e.g. '{seqid}0001'
Definition adata.h:58
IMAP command structure.
Definition private.h:176
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_read_literal()

int imap_read_literal ( FILE * fp,
struct ImapAccountData * adata,
unsigned long bytes,
struct Progress * progress )

Read bytes bytes from server into file.

Parameters
fpFile handle for email file
adataImap Account data
bytesNumber of bytes to read
progressProgress bar
Return values
0Success
-1Failure

Not explicitly buffered, relies on FILE buffering.

Note
Strips \r from \r\n. Apparently even literals use \r\n-terminated strings ?!

Definition at line 704 of file imap.c.

706{
707 char c;
708 bool r = false;
709 struct Buffer buf = { 0 }; // Do not allocate, maybe it won't be used
710
711 const short c_debug_level = cs_subset_number(NeoMutt->sub, "debug_level");
712 if (c_debug_level >= IMAP_LOG_LTRL)
713 buf_alloc(&buf, bytes + 1);
714
715 mutt_debug(LL_DEBUG2, "reading %lu byte literal from server\n", bytes);
716
717 /* For large transfers, calculate checkpoint for progress logging */
718 unsigned long checkpoint = bytes / 10; // Log every 10%
719 if (checkpoint == 0)
720 checkpoint = bytes; // For small transfers, don't log progress
721
722 time_t start_time = mutt_date_now();
723 time_t last_progress = start_time;
724 time_t last_activity = start_time;
725
726 /* Get timeout value - use imap_poll_timeout or default to 60 seconds */
727 const short c_imap_poll_timeout = cs_subset_number(NeoMutt->sub, "imap_poll_timeout");
728 const int stall_timeout = (c_imap_poll_timeout > 0) ? c_imap_poll_timeout : 60;
729
730 for (unsigned long pos = 0; pos < bytes; pos++)
731 {
732 /* Check for user interrupt (Ctrl-C) periodically */
733 if ((pos % 4096) == 0)
734 {
735 if (SigInt)
736 {
737 mutt_debug(LL_DEBUG1, "Literal read interrupted by user at %lu/%lu bytes\n",
738 pos, bytes);
739 mutt_error(_("Download interrupted"));
740 SigInt = false;
741 adata->status = IMAP_FATAL;
742 buf_dealloc(&buf);
743 return -1;
744 }
745
746 /* Check for stalled transfer */
747 time_t now = mutt_date_now();
748 if ((now - last_activity) > stall_timeout)
749 {
750 mutt_debug(LL_DEBUG1, "Literal read stalled at %lu/%lu bytes (no data for %d seconds)\n",
751 pos, bytes, stall_timeout);
752 mutt_error(_("Download stalled - no data received for %d seconds"), stall_timeout);
753 adata->status = IMAP_FATAL;
754 buf_dealloc(&buf);
755 return -1;
756 }
757 }
758
759 if (mutt_socket_readchar(adata->conn, &c) != 1)
760 {
761 time_t duration = mutt_date_now() - start_time;
762 mutt_debug(LL_DEBUG1, "Error during literal read at byte %lu/%lu (%.1f%% complete)\n",
763 pos, bytes, (bytes > 0) ? ((double) pos / bytes * 100.0) : 0.0);
764 mutt_debug(LL_DEBUG1, "Read failed after %ld seconds (errno=%d: %s)\n",
765 (long) duration, errno, strerror(errno));
766 adata->status = IMAP_FATAL;
767
768 buf_dealloc(&buf);
769 return -1;
770 }
771
772 last_activity = mutt_date_now();
773
774 if (r && (c != '\n'))
775 fputc('\r', fp);
776
777 if (c == '\r')
778 {
779 r = true;
780 continue;
781 }
782 else
783 {
784 r = false;
785 }
786
787 fputc(c, fp);
788
789 if ((pos % 1024) == 0)
790 progress_update(progress, pos, -1);
791
792 /* Log progress every 10% for large transfers */
793 if ((checkpoint > 0) && ((pos % checkpoint) == 0) && (pos > 0))
794 {
795 time_t now = mutt_date_now();
796 if (now > last_progress)
797 {
798 mutt_debug(LL_DEBUG2, "Literal read progress: %lu/%lu bytes (%.1f%%)\n",
799 pos, bytes, ((double) pos / bytes * 100.0));
800 last_progress = now;
801 }
802 }
803
804 if (c_debug_level >= IMAP_LOG_LTRL)
805 buf_addch(&buf, c);
806 }
807
808 time_t duration = mutt_date_now() - start_time;
809 if (duration > 0)
810 {
811 mutt_debug(LL_DEBUG2, "Literal read complete: %lu bytes in %ld seconds\n",
812 bytes, (long) duration);
813 }
814
815 if (c_debug_level >= IMAP_LOG_LTRL)
816 {
817 mutt_debug(IMAP_LOG_LTRL, "\n%s", buf.data);
818 buf_dealloc(&buf);
819 }
820 return 0;
821}
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition buffer.c:377
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:241
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:337
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition helpers.c:143
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define IMAP_LOG_LTRL
Log literal values.
Definition private.h:48
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:457
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition progress.c:80
volatile sig_atomic_t SigInt
true after SIGINT is received
Definition signal.c:68
int mutt_socket_readchar(struct Connection *conn, char *c)
Simple read buffering to speed things up.
Definition socket.c:200
char * data
Pointer to data.
Definition buffer.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_expunge_mailbox()

void imap_expunge_mailbox ( struct Mailbox * m,
bool resort )

Purge messages from the server.

Parameters
mMailbox
resortTrigger a resort?

Purge IMAP portion of expunged messages from the context. Must not be done while something has a handle on any headers (eg inside pager or editor). That is, check IMAP_REOPEN_ALLOW.

Definition at line 849 of file imap.c.

850{
852 struct ImapMboxData *mdata = imap_mdata_get(m);
853 if (!adata || !mdata)
854 return;
855
856 struct Email *e = NULL;
857
858#ifdef USE_HCACHE
859 imap_hcache_open(adata, mdata, false);
860#endif
861
862 for (int i = 0; i < m->msg_count; i++)
863 {
864 e = m->emails[i];
865 if (!e)
866 break;
867
868 if (e->index == INT_MAX)
869 {
870 mutt_debug(LL_DEBUG2, "Expunging message UID %u\n", imap_edata_get(e)->uid);
871
872 e->deleted = true;
873
874 imap_cache_del(m, e);
875#ifdef USE_HCACHE
876 imap_hcache_del(mdata, imap_edata_get(e)->uid);
877#endif
878
879 mutt_hash_int_delete(mdata->uid_hash, imap_edata_get(e)->uid, e);
880
881 imap_edata_free((void **) &e->edata);
882 }
883 else
884 {
885 /* NeoMutt has several places where it turns off e->active as a
886 * hack. For example to avoid FLAG updates, or to exclude from
887 * imap_exec_msg_set.
888 *
889 * Unfortunately, when a reopen is allowed and the IMAP_EXPUNGE_PENDING
890 * flag becomes set (e.g. a flag update to a modified header),
891 * this function will be called by imap_cmd_finish().
892 *
893 * The ctx_update_tables() will free and remove these "inactive" headers,
894 * despite that an EXPUNGE was not received for them.
895 * This would result in memory leaks and segfaults due to dangling
896 * pointers in the msn_index and uid_hash.
897 *
898 * So this is another hack to work around the hacks. We don't want to
899 * remove the messages, so make sure active is on. */
900 e->active = true;
901 }
902 }
903
904#ifdef USE_HCACHE
905 imap_hcache_close(mdata);
906#endif
907
909 if (resort)
910 {
912 }
913}
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition mailbox.c:232
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition mailbox.h:183
@ NT_MAILBOX_UPDATE
Update internal tables.
Definition mailbox.h:184
void imap_edata_free(void **ptr)
Free the private Email data - Implements Email::edata_free() -.
Definition edata.c:39
void mutt_hash_int_delete(struct HashTable *table, unsigned int intkey, const void *data)
Remove an element from a Hash Table.
Definition hash.c:446
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition adata.c:162
struct ImapEmailData * imap_edata_get(struct Email *e)
Get the private data for this Email.
Definition edata.c:66
struct ImapMboxData * imap_mdata_get(struct Mailbox *m)
Get the Mailbox data for this mailbox.
Definition mdata.c:61
int imap_cache_del(struct Mailbox *m, struct Email *e)
Delete an email from the body cache.
Definition message.c:1901
void imap_hcache_open(struct ImapAccountData *adata, struct ImapMboxData *mdata, bool create)
Open a header cache.
Definition util.c:307
void imap_hcache_close(struct ImapMboxData *mdata)
Close the header cache.
Definition util.c:348
int imap_hcache_del(struct ImapMboxData *mdata, unsigned int uid)
Delete an item from the header cache.
Definition util.c:406
void * adata
Private data (for Mailbox backends)
Definition account.h:42
The envelope/body of an email.
Definition email.h:39
void * edata
Driver-specific data.
Definition email.h:74
bool active
Message is not to be removed.
Definition email.h:76
bool deleted
Email is deleted.
Definition email.h:78
int index
The absolute (unsorted) message number.
Definition email.h:110
IMAP-specific Account data -.
Definition adata.h:40
IMAP-specific Mailbox data -.
Definition mdata.h:40
struct HashTable * uid_hash
Hash Table: "uid" -> Email.
Definition mdata.h:60
int msg_count
Total number of messages.
Definition mailbox.h:90
void * mdata
Driver specific data.
Definition mailbox.h:134
struct Email ** emails
Array of Emails.
Definition mailbox.h:98
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_login()

int imap_login ( struct ImapAccountData * adata)

Open an IMAP connection.

Parameters
adataImap Account data
Return values
0Success
-1Failure

Ensure ImapAccountData is connected and logged into the imap server.

Definition at line 2013 of file imap.c.

2014{
2015 if (!adata)
2016 return -1;
2017
2018 if (adata->state == IMAP_DISCONNECTED)
2019 {
2020 buf_reset(&adata->cmdbuf); // purge outstanding queued commands
2021 imap_open_connection(adata);
2022 }
2023 if (adata->state == IMAP_CONNECTED)
2024 {
2026 {
2027 adata->state = IMAP_AUTHENTICATED;
2028 FREE(&adata->capstr);
2029 if (adata->conn->ssf != 0)
2030 {
2031 mutt_debug(LL_DEBUG2, "Communication encrypted at %d bits\n",
2032 adata->conn->ssf);
2033 }
2034 }
2035 else
2036 {
2038 }
2039 }
2040 if (adata->state == IMAP_AUTHENTICATED)
2041 {
2042 /* capabilities may have changed */
2043 imap_exec(adata, "CAPABILITY", IMAP_CMD_PASS);
2044
2045#ifdef USE_ZLIB
2046 /* RFC4978 */
2047 const bool c_imap_deflate = cs_subset_bool(NeoMutt->sub, "imap_deflate");
2048 if ((adata->capabilities & IMAP_CAP_COMPRESS) && c_imap_deflate &&
2049 (imap_exec(adata, "COMPRESS DEFLATE", IMAP_CMD_PASS) == IMAP_EXEC_SUCCESS))
2050 {
2051 mutt_debug(LL_DEBUG2, "IMAP compression is enabled on connection to %s\n",
2052 adata->conn->account.host);
2053 mutt_zstrm_wrap_conn(adata->conn);
2054 }
2055#endif
2056
2057 /* enable RFC2971, if the server supports that */
2058 const bool c_imap_send_id = cs_subset_bool(NeoMutt->sub, "imap_send_id");
2059 if (c_imap_send_id && (adata->capabilities & IMAP_CAP_ID))
2060 {
2061 imap_exec(adata, "ID (\"name\" \"NeoMutt\" \"version\" \"" PACKAGE_VERSION "\")",
2063 }
2064
2065 /* enable RFC6855, if the server supports that */
2066 const bool c_imap_rfc5161 = cs_subset_bool(NeoMutt->sub, "imap_rfc5161");
2067 if (c_imap_rfc5161 && (adata->capabilities & IMAP_CAP_ENABLE))
2068 imap_exec(adata, "ENABLE UTF8=ACCEPT", IMAP_CMD_QUEUE);
2069
2070 /* enable QRESYNC. Advertising QRESYNC also means CONDSTORE
2071 * is supported (even if not advertised), so flip that bit. */
2072 if (adata->capabilities & IMAP_CAP_QRESYNC)
2073 {
2075 const bool c_imap_qresync = cs_subset_bool(NeoMutt->sub, "imap_qresync");
2076 if (c_imap_rfc5161 && c_imap_qresync)
2077 imap_exec(adata, "ENABLE QRESYNC", IMAP_CMD_QUEUE);
2078 }
2079
2080 /* get root delimiter, '/' as default */
2081 adata->delim = '/';
2082 imap_exec(adata, "LIST \"\" \"\"", IMAP_CMD_QUEUE);
2083
2084 /* we may need the root delimiter before we open a mailbox */
2085 imap_exec(adata, NULL, IMAP_CMD_NONE);
2086
2087 /* select the mailbox that used to be open before disconnect */
2088 if (adata->mailbox)
2089 {
2090 imap_mbox_select(adata->mailbox);
2091 }
2092 }
2093
2094 if (adata->state < IMAP_AUTHENTICATED)
2095 return -1;
2096
2097 return 0;
2098}
@ IMAP_AUTH_SUCCESS
Authentication successful.
Definition auth.h:40
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
void mutt_account_unsetpass(struct ConnAccount *cac)
Unset ConnAccount's password.
int imap_authenticate(struct ImapAccountData *adata)
Authenticate to an IMAP server.
Definition auth.c:116
int imap_open_connection(struct ImapAccountData *adata)
Open an IMAP connection.
Definition imap.c:921
static void imap_mbox_select(struct Mailbox *m)
Select a Mailbox.
Definition imap.c:1980
char host[128]
Server to login to.
Definition connaccount.h:60
struct ConnAccount account
Account details: username, password, etc.
Definition connection.h:49
char delim
Path delimiter.
Definition adata.h:79
struct Mailbox * mailbox
Current selected mailbox.
Definition adata.h:80
struct Buffer cmdbuf
Command queue.
Definition adata.h:77
void mutt_zstrm_wrap_conn(struct Connection *conn)
Wrap a compression layer around a Connection.
Definition zstrm.c:297
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_sync_message_for_copy()

int imap_sync_message_for_copy ( struct Mailbox * m,
struct Email * e,
struct Buffer * cmd,
enum QuadOption * err_continue )

Update server to reflect the flags of a single message.

Parameters
[in]mMailbox
[in]eEmail
[in]cmdBuffer for the command string
[out]err_continueDid the user force a continue?
Return values
0Success
-1Failure

Update the IMAP server to reflect the flags for a single message before performing a "UID COPY".

Note
This does not sync the "deleted" flag state, because it is not desirable to propagate that flag into the copy.

Definition at line 1114 of file imap.c.

1116{
1118 struct ImapEmailData *edata = imap_edata_get(e);
1119
1120 if (!adata || (adata->mailbox != m) || !e)
1121 return -1;
1122
1123 if (!compare_flags_for_copy(e))
1124 {
1125 if (e->deleted == edata->deleted)
1126 e->changed = false;
1127 return 0;
1128 }
1129
1130 buf_printf(cmd, "UID STORE %u", edata->uid);
1131
1132 struct Buffer *flags = buf_pool_get();
1133
1134 set_flag(m, MUTT_ACL_SEEN, e->read, "\\Seen ", flags);
1135 set_flag(m, MUTT_ACL_WRITE, e->old, "Old ", flags);
1136 set_flag(m, MUTT_ACL_WRITE, e->flagged, "\\Flagged ", flags);
1137 set_flag(m, MUTT_ACL_WRITE, e->replied, "\\Answered ", flags);
1138 set_flag(m, MUTT_ACL_DELETE, edata->deleted, "\\Deleted ", flags);
1139
1140 if (m->rights & MUTT_ACL_WRITE)
1141 {
1142 /* restore system flags */
1143 if (edata->flags_system)
1144 buf_addstr(flags, edata->flags_system);
1145
1146 /* set custom flags */
1147 struct Buffer *tags = buf_pool_get();
1149 if (!buf_is_empty(tags))
1150 buf_addstr(flags, buf_string(tags));
1151 buf_pool_release(&tags);
1152 }
1153
1155 buf_fix_dptr(flags);
1156
1157 /* UW-IMAP is OK with null flags, Cyrus isn't. The only solution is to
1158 * explicitly revoke all system flags (if we have permission) */
1159 if (buf_is_empty(flags))
1160 {
1161 set_flag(m, MUTT_ACL_SEEN, true, "\\Seen ", flags);
1162 set_flag(m, MUTT_ACL_WRITE, true, "Old ", flags);
1163 set_flag(m, MUTT_ACL_WRITE, true, "\\Flagged ", flags);
1164 set_flag(m, MUTT_ACL_WRITE, true, "\\Answered ", flags);
1165 set_flag(m, MUTT_ACL_DELETE, !edata->deleted, "\\Deleted ", flags);
1166
1167 /* erase custom flags */
1168 if ((m->rights & MUTT_ACL_WRITE) && edata->flags_remote)
1169 buf_addstr(flags, edata->flags_remote);
1170
1172 buf_fix_dptr(flags);
1173
1174 buf_addstr(cmd, " -FLAGS.SILENT (");
1175 }
1176 else
1177 {
1178 buf_addstr(cmd, " FLAGS.SILENT (");
1179 }
1180
1181 buf_addstr(cmd, buf_string(flags));
1182 buf_addstr(cmd, ")");
1183
1184 int rc = -1;
1185
1186 /* after all this it's still possible to have no flags, if you
1187 * have no ACL rights */
1188 if (!buf_is_empty(flags) &&
1189 (imap_exec(adata, cmd->data, IMAP_CMD_NONE) != IMAP_EXEC_SUCCESS) &&
1190 err_continue && (*err_continue != MUTT_YES))
1191 {
1192 *err_continue = imap_continue("imap_sync_message: STORE failed", adata->buf);
1193 if (*err_continue != MUTT_YES)
1194 goto done;
1195 }
1196
1197 /* server have now the updated flags */
1198 FREE(&edata->flags_remote);
1199 struct Buffer *flags_remote = buf_pool_get();
1200 driver_tags_get_with_hidden(&e->tags, flags_remote);
1201 edata->flags_remote = buf_strdup(flags_remote);
1202 buf_pool_release(&flags_remote);
1203
1204 if (e->deleted == edata->deleted)
1205 e->changed = false;
1206
1207 rc = 0;
1208
1209done:
1210 buf_pool_release(&flags);
1211 return rc;
1212}
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition buffer.c:182
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
@ MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition mailbox.h:71
@ MUTT_ACL_DELETE
Delete a message.
Definition mailbox.h:63
@ MUTT_ACL_SEEN
Change the 'seen' status of a message.
Definition mailbox.h:70
enum QuadOption imap_continue(const char *msg, const char *resp)
Display a message and ask the user if they want to go on.
Definition util.c:654
static void set_flag(struct Mailbox *m, AclFlags aclflag, bool flag, const char *str, struct Buffer *flags)
Append str to flags if we currently have permission according to aclflag.
Definition imap.c:287
static bool compare_flags_for_copy(struct Email *e)
Compare local flags against the server.
Definition imap.c:307
void mutt_str_remove_trailing_ws(char *s)
Trim trailing whitespace from a string.
Definition string.c:570
bool read
Email is read.
Definition email.h:50
bool old
Email is seen, but unread.
Definition email.h:49
bool changed
Email has been edited.
Definition email.h:77
bool flagged
Marked important?
Definition email.h:47
bool replied
Email has been replied to.
Definition email.h:51
struct TagList tags
For drivers that support server tagging.
Definition email.h:72
IMAP-specific Email data -.
Definition edata.h:35
char * flags_remote
Remote flags.
Definition edata.h:49
bool deleted
Email has been deleted.
Definition edata.h:39
char * flags_system
System flags.
Definition edata.h:48
AclFlags rights
ACL bits, see AclFlags.
Definition mailbox.h:121
void driver_tags_get_with_hidden(struct TagList *tl, struct Buffer *tags)
Get all tags, also hidden ones, separated by space.
Definition tags.c:175
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_has_flag()

bool imap_has_flag ( struct ListHead * flag_list,
const char * flag )

Does the flag exist in the list.

Parameters
flag_listList of server flags
flagFlag to find
Return values
trueFlag exists

Do a caseless comparison of the flag against a flag list, return true if found or flag list has '*'. Note that "flag" might contain additional whitespace at the end, so we really need to compare up to the length of each element in "flag_list".

Definition at line 1054 of file imap.c.

1055{
1056 if (STAILQ_EMPTY(flag_list))
1057 return false;
1058
1059 const size_t flaglen = mutt_str_len(flag);
1060 struct ListNode *np = NULL;
1061 STAILQ_FOREACH(np, flag_list, entries)
1062 {
1063 const size_t nplen = strlen(np->data);
1064 if ((flaglen >= nplen) && ((flag[nplen] == '\0') || (flag[nplen] == ' ')) &&
1065 mutt_istrn_equal(np->data, flag, nplen))
1066 {
1067 return true;
1068 }
1069
1070 if (mutt_str_equal(np->data, "\\*"))
1071 return true;
1072 }
1073
1074 return false;
1075}
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
bool mutt_istrn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition string.c:457
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define STAILQ_EMPTY(head)
Definition queue.h:382
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_adata_find()

int imap_adata_find ( const char * path,
struct ImapAccountData ** adata,
struct ImapMboxData ** mdata )

Find the Account data for this path.

Parameters
pathPath to search for
adataImap Account data
mdataImap Mailbox data
Return values
0Success
-1Failure

Definition at line 73 of file util.c.

75{
76 struct ConnAccount cac = { { 0 } };
77 struct ImapAccountData *tmp_adata = NULL;
78 char tmp[1024] = { 0 };
79
80 if (imap_parse_path(path, &cac, tmp, sizeof(tmp)) < 0)
81 return -1;
82
83 struct Account **ap = NULL;
85 {
86 struct Account *a = *ap;
87 if (a->type != MUTT_IMAP)
88 continue;
89
90 tmp_adata = a->adata;
91 if (!tmp_adata)
92 continue;
93 if (imap_account_match(&tmp_adata->conn->account, &cac))
94 {
95 if (mdata)
96 {
97 *mdata = imap_mdata_new(tmp_adata, tmp);
98 }
99 *adata = tmp_adata;
100 return 0;
101 }
102 }
103 mutt_debug(LL_DEBUG3, "no ImapAccountData found\n");
104 return -1;
105}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
@ MUTT_IMAP
'IMAP' Mailbox type
Definition mailbox.h:49
struct ImapMboxData * imap_mdata_new(struct ImapAccountData *adata, const char *name)
Allocate and initialise a new ImapMboxData structure.
Definition mdata.c:74
@ LL_DEBUG3
Log at debug level 3.
Definition logging2.h:47
A group of associated Mailboxes.
Definition account.h:36
enum MailboxType type
Type of Mailboxes this Account contains.
Definition account.h:37
Login details for a remote server.
Definition connaccount.h:59
struct AccountArray accounts
All Accounts.
Definition neomutt.h:50
int imap_parse_path(const char *path, struct ConnAccount *cac, char *mailbox, size_t mailboxlen)
Parse an IMAP mailbox name into ConnAccount, name.
Definition util.c:482
bool imap_account_match(const struct ConnAccount *a1, const struct ConnAccount *a2)
Compare two Accounts.
Definition util.c:1106
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_reopen_mailbox()

int imap_reopen_mailbox ( struct ImapAccountData * adata)

Re-SELECT the current mailbox after reconnecting.

Parameters
adataImap Account data (must be in IMAP_AUTHENTICATED state)
Return values
0Success
-1Failure

After a connection drop and successful reconnect, re-SELECT the previously open mailbox, clear stale message state, and re-fetch all headers so the index is repopulated. This avoids the destructive mx_fastclose_mailbox() path that used to leave the user with an empty screen.

Definition at line 2261 of file imap.c.

2262{
2263 if (!adata || !adata->mailbox)
2264 return -1;
2265
2266 struct Mailbox *m = adata->mailbox;
2267 struct ImapMboxData *mdata = imap_mdata_get(m);
2268 if (!mdata)
2269 return -1;
2270
2271 mutt_debug(LL_DEBUG1, "Re-selecting mailbox %s after reconnect\n", mdata->name);
2272
2273 for (int i = 0; i < m->msg_count; i++)
2274 {
2275 struct Email *e = m->emails[i];
2276 if (!e)
2277 continue;
2278 imap_edata_free((void **) &e->edata);
2279 email_free(&m->emails[i]);
2280 }
2281 m->msg_count = 0;
2282 m->msg_unread = 0;
2283 m->msg_flagged = 0;
2284 m->msg_new = 0;
2285 m->msg_deleted = 0;
2286 m->size = 0;
2287 m->vcount = 0;
2288
2290
2291 mdata->new_mail_count = 0;
2292 mdata->reopen = IMAP_OPEN_NONE;
2294
2295 int count = 0;
2296 if (imap_select_and_poll(m, &count) < 0)
2297 goto fail;
2298
2299 mx_alloc_memory(m, count);
2300
2301 if ((count > 0) && (imap_read_headers(m, 1, count, true) < 0))
2302 goto fail;
2303
2304 mutt_debug(LL_DEBUG1, "Reopened mailbox %s with %d messages\n", mdata->name, m->msg_count);
2307 return 0;
2308
2309fail:
2310 mutt_debug(LL_DEBUG1, "Failed to reopen mailbox %s\n", mdata->name);
2311 if (adata->state == IMAP_SELECTED)
2312 adata->state = IMAP_AUTHENTICATED;
2313 return -1;
2314}
void email_free(struct Email **ptr)
Free an Email.
Definition email.c:46
int imap_read_headers(struct Mailbox *m, unsigned int msn_begin, unsigned int msn_end, bool initial_download)
Read headers from the server.
Definition message.c:1366
void imap_mdata_cache_reset(struct ImapMboxData *mdata)
Release and clear cache data of ImapMboxData structure.
Definition util.c:111
static int imap_select_and_poll(struct Mailbox *m, int *countp)
Send SELECT and parse the untagged responses.
Definition imap.c:2112
void mx_alloc_memory(struct Mailbox *m, int req_size)
Create storage for the emails.
Definition mx.c:1208
ImapOpenFlags reopen
Flags, e.g. IMAP_REOPEN_ALLOW.
Definition mdata.h:45
unsigned int new_mail_count
Set when EXISTS notifies of new mail.
Definition mdata.h:47
ImapOpenFlags check_status
Flags, e.g. IMAP_NEWMAIL_PENDING.
Definition mdata.h:46
char * name
Mailbox name.
Definition mdata.h:41
A mailbox.
Definition mailbox.h:81
int vcount
The number of virtual messages.
Definition mailbox.h:101
int msg_new
Number of new messages.
Definition mailbox.h:94
int msg_deleted
Number of deleted messages.
Definition mailbox.h:95
off_t size
Size of the Mailbox.
Definition mailbox.h:86
int msg_flagged
Number of flagged messages.
Definition mailbox.h:92
int msg_unread
Number of unread messages.
Definition mailbox.h:91
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_authenticate()

int imap_authenticate ( struct ImapAccountData * adata)

Authenticate to an IMAP server.

Parameters
adataImap Account data
Return values
enumImapAuthRes, e.g. IMAP_AUTH_SUCCESS

Attempt to authenticate using either user-specified authentication method if specified, or any.

Definition at line 116 of file auth.c.

117{
118 int rc = IMAP_AUTH_FAILURE;
119
120 const struct Slist *c_imap_authenticators = cs_subset_slist(NeoMutt->sub, "imap_authenticators");
121 if (c_imap_authenticators && (c_imap_authenticators->count > 0))
122 {
123 mutt_debug(LL_DEBUG2, "Trying user-defined imap_authenticators\n");
124
125 /* Try user-specified list of authentication methods */
126 struct ListNode *np = NULL;
127 STAILQ_FOREACH(np, &c_imap_authenticators->head, entries)
128 {
129 mutt_debug(LL_DEBUG2, "Trying method %s\n", np->data);
130
131 for (size_t i = 0; i < countof(ImapAuthenticators); i++)
132 {
133 const struct ImapAuth *auth = &ImapAuthenticators[i];
134 if (!auth->method || mutt_istr_equal(auth->method, np->data))
135 {
136 rc = auth->authenticate(adata, np->data);
137 if (rc == IMAP_AUTH_SUCCESS)
138 {
139 return rc;
140 }
141 }
142 }
143 }
144 }
145 else
146 {
147 /* Fall back to default: any authenticator */
148 mutt_debug(LL_DEBUG2, "Trying pre-defined imap_authenticators\n");
149
150 for (size_t i = 0; i < countof(ImapAuthenticators); i++)
151 {
152 rc = ImapAuthenticators[i].authenticate(adata, NULL);
153 if (rc == IMAP_AUTH_SUCCESS)
154 return rc;
155 }
156 }
157
158 mutt_error(_("No authenticators available or wrong credentials"));
159 return rc;
160}
@ IMAP_AUTH_FAILURE
Authentication failed.
Definition auth.h:41
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition helpers.c:242
static const struct ImapAuth ImapAuthenticators[]
Accepted authentication methods.
Definition auth.c:65
#define countof(x)
Definition memory.h:49
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:677
IMAP authentication multiplexor.
Definition auth.c:47
enum ImapAuthRes(* authenticate)(struct ImapAccountData *adata, const char *method)
Definition auth.c:56
const char * method
Name of authentication method supported, NULL means variable.
Definition auth.c:58
String list.
Definition slist.h:37
struct ListHead head
List containing values.
Definition slist.h:38
size_t count
Number of values in list.
Definition slist.h:39
+ Here is the caller graph for this function:

◆ imap_cmd_start()

int imap_cmd_start ( struct ImapAccountData * adata,
const char * cmdstr )

Given an IMAP command, send it to the server.

Parameters
adataImap Account data
cmdstrCommand string to send
Return values
0Success
<0Failure, e.g. IMAP_RES_BAD

If cmdstr is NULL, sends queued commands.

Definition at line 1216 of file command.c.

1217{
1218 return cmd_start(adata, cmdstr, IMAP_CMD_NONE);
1219}
static int cmd_start(struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
Start a new IMAP command.
Definition command.c:271
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_cmd_step()

int imap_cmd_step ( struct ImapAccountData * adata)

Reads server responses from an IMAP command.

Parameters
adataImap Account data
Return values
0Success
<0Failure, e.g. IMAP_RES_BAD

detects tagged completion response, handles untagged messages, can read arbitrarily large strings (using malloc, so don't make it too large!).

Definition at line 1230 of file command.c.

1231{
1232 if (!adata)
1233 return -1;
1234
1235 size_t len = 0;
1236 int c;
1237 int rc;
1238 int stillrunning = 0;
1239 struct ImapCommand *cmd = NULL;
1240
1241 if (adata->status == IMAP_FATAL)
1242 {
1243 cmd_handle_fatal(adata);
1244 return IMAP_RES_BAD;
1245 }
1246
1247 /* read into buffer, expanding buffer as necessary until we have a full
1248 * line */
1249 do
1250 {
1251 if (len == adata->blen)
1252 {
1253 MUTT_MEM_REALLOC(&adata->buf, adata->blen + IMAP_CMD_BUFSIZE, char);
1254 adata->blen = adata->blen + IMAP_CMD_BUFSIZE;
1255 mutt_debug(LL_DEBUG3, "grew buffer to %zu bytes\n", adata->blen);
1256 }
1257
1258 /* back up over '\0' */
1259 if (len)
1260 len--;
1261
1262 mutt_debug(LL_DEBUG3, "reading from socket (fd=%d, state=%d)\n",
1263 adata->conn ? adata->conn->fd : -1, adata->state);
1264 time_t read_start = mutt_date_now();
1265
1266 c = mutt_socket_readln_d(adata->buf + len, adata->blen - len, adata->conn, MUTT_SOCK_LOG_FULL);
1267
1268 time_t read_duration = mutt_date_now() - read_start;
1269 if (read_duration > 1)
1270 {
1271 mutt_debug(LL_DEBUG1, "socket read took %ld seconds\n", (long) read_duration);
1272 }
1273
1274 if (c <= 0)
1275 {
1276 mutt_debug(LL_DEBUG1, "Error reading server response (rc=%d, errno=%d: %s)\n",
1277 c, errno, strerror(errno));
1278 mutt_debug(LL_DEBUG1, "Connection state: fd=%d, state=%d, status=%d\n",
1279 adata->conn ? adata->conn->fd : -1, adata->state, adata->status);
1280 cmd_handle_fatal(adata);
1281 return IMAP_RES_BAD;
1282 }
1283
1284 len += c;
1285 }
1286 /* if we've read all the way to the end of the buffer, we haven't read a
1287 * full line (mutt_socket_readln strips the \r, so we always have at least
1288 * one character free when we've read a full line) */
1289 while (len == adata->blen);
1290
1291 /* don't let one large string make cmd->buf hog memory forever */
1292 if ((adata->blen > IMAP_CMD_BUFSIZE) && (len <= IMAP_CMD_BUFSIZE))
1293 {
1294 MUTT_MEM_REALLOC(&adata->buf, IMAP_CMD_BUFSIZE, char);
1295 adata->blen = IMAP_CMD_BUFSIZE;
1296 mutt_debug(LL_DEBUG3, "shrank buffer to %zu bytes\n", adata->blen);
1297 }
1298
1299 adata->lastread = mutt_date_now();
1300
1301 /* handle untagged messages. The caller still gets its shot afterwards. */
1302 if ((mutt_str_startswith(adata->buf, "* ") ||
1303 mutt_str_startswith(imap_next_word(adata->buf), "OK [")) &&
1304 cmd_handle_untagged(adata))
1305 {
1306 return IMAP_RES_BAD;
1307 }
1308
1309 /* server demands a continuation response from us */
1310 if (adata->buf[0] == '+')
1311 return IMAP_RES_RESPOND;
1312
1313 /* Look for tagged command completions.
1314 *
1315 * Some response handlers can end up recursively calling
1316 * imap_cmd_step() and end up handling all tagged command
1317 * completions.
1318 * (e.g. FETCH->set_flag->set_header_color->~h pattern match.)
1319 *
1320 * Other callers don't even create an adata->cmds entry.
1321 *
1322 * For both these cases, we default to returning OK */
1323 rc = IMAP_RES_OK;
1324 c = adata->lastcmd;
1325 do
1326 {
1327 cmd = &adata->cmds[c];
1328 if (cmd->state == IMAP_RES_NEW)
1329 {
1330 if (mutt_str_startswith(adata->buf, cmd->seq))
1331 {
1332 if (!stillrunning)
1333 {
1334 /* first command in queue has finished - move queue pointer up */
1335 adata->lastcmd = (adata->lastcmd + 1) % adata->cmdslots;
1336 }
1337 cmd->state = cmd_status(adata->buf);
1338 rc = cmd->state;
1339 if (cmd->state == IMAP_RES_NO || cmd->state == IMAP_RES_BAD)
1340 {
1341 mutt_message(_("IMAP command failed: %s"), adata->buf);
1342 }
1343 }
1344 else
1345 {
1346 stillrunning++;
1347 }
1348 }
1349
1350 c = (c + 1) % adata->cmdslots;
1351 } while (c != adata->nextcmd);
1352
1353 if (stillrunning)
1354 {
1355 rc = IMAP_RES_CONTINUE;
1356 }
1357 else
1358 {
1359 mutt_debug(LL_DEBUG3, "IMAP queue drained\n");
1360 imap_cmd_finish(adata);
1361 }
1362
1363 return rc;
1364}
#define mutt_message(...)
Definition logging2.h:93
static int cmd_handle_untagged(struct ImapAccountData *adata)
Fallback parser for otherwise unhandled messages.
Definition command.c:1120
static int cmd_status(const char *s)
Parse response line for tagged OK/NO/BAD.
Definition command.c:307
static void cmd_handle_fatal(struct ImapAccountData *adata)
When ImapAccountData is in fatal state, do what we can.
Definition command.c:184
#define IMAP_CMD_BUFSIZE
Default buffer size for IMAP commands.
Definition command.c:63
void imap_cmd_finish(struct ImapAccountData *adata)
Attempt to perform cleanup.
Definition command.c:1511
#define IMAP_RES_RESPOND
+
Definition private.h:56
#define IMAP_RES_NEW
ImapCommand.state additions.
Definition private.h:57
#define IMAP_RES_NO
<tag> NO ...
Definition private.h:52
#define IMAP_RES_CONTINUE
* ...
Definition private.h:55
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition util.c:829
#define IMAP_RES_BAD
<tag> BAD ...
Definition private.h:53
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition memory.h:55
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
int mutt_socket_readln_d(char *buf, size_t buflen, struct Connection *conn, int dbg)
Read a line from a socket.
Definition socket.c:238
#define MUTT_SOCK_LOG_FULL
Log everything including full protocol.
Definition socket.h:53
int fd
Socket file descriptor.
Definition connection.h:53
time_t lastread
last time we read a command for the server
Definition adata.h:59
size_t blen
Command buffer length.
Definition adata.h:62
int state
Command state, e.g. IMAP_RES_NEW.
Definition private.h:178
char seq[SEQ_LEN+1]
Command tag, e.g. 'a0001'.
Definition private.h:177
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_cmd_finish()

void imap_cmd_finish ( struct ImapAccountData * adata)

Attempt to perform cleanup.

Parameters
adataImap Account data

If a reopen is allowed, it attempts to perform cleanup (eg fetch new mail if detected, do expunge). Called automatically by imap_cmd_step(), but may be called at any time.

mdata->check_status is set and will be used later by imap_check_mailbox().

Definition at line 1511 of file command.c.

1512{
1513 if (!adata)
1514 return;
1515
1516 if (adata->status == IMAP_FATAL)
1517 {
1518 adata->closing = false;
1519 cmd_handle_fatal(adata);
1520 return;
1521 }
1522
1523 if (!(adata->state >= IMAP_SELECTED) || !adata->mailbox || adata->closing)
1524 {
1525 adata->closing = false;
1526 return;
1527 }
1528
1529 adata->closing = false;
1530
1531 struct ImapMboxData *mdata = imap_mdata_get(adata->mailbox);
1532
1533 if (mdata && (mdata->reopen & IMAP_REOPEN_ALLOW) && !(mdata->reopen & IMAP_SYNC_IN_PROGRESS))
1534 {
1535 // First remove expunged emails from the msn_index
1536 if (mdata->reopen & IMAP_EXPUNGE_PENDING)
1537 {
1538 mutt_debug(LL_DEBUG2, "Expunging mailbox\n");
1539 imap_expunge_mailbox(adata->mailbox, true);
1540 /* Detect whether we've gotten unexpected EXPUNGE messages */
1541 if (!(mdata->reopen & IMAP_EXPUNGE_EXPECTED))
1542 mdata->check_status |= IMAP_EXPUNGE_PENDING;
1544 }
1545
1546 // Then add new emails to it
1547 if (mdata->reopen & IMAP_NEWMAIL_PENDING)
1548 {
1549 const size_t max_msn = imap_msn_highest(&mdata->msn);
1550 if (mdata->new_mail_count > max_msn)
1551 {
1552 if (!(mdata->reopen & IMAP_EXPUNGE_PENDING))
1553 mdata->check_status |= IMAP_NEWMAIL_PENDING;
1554
1555 mutt_debug(LL_DEBUG2, "Fetching new mails from %zd to %u\n",
1556 max_msn + 1, mdata->new_mail_count);
1557 imap_read_headers(adata->mailbox, max_msn + 1, mdata->new_mail_count, false);
1558 }
1559 }
1560
1561 /* imap_read_headers may have triggered a fatal error that NULLed
1562 * adata->mailbox. Re-check before accessing mdata further. */
1563 if (!adata->mailbox)
1564 {
1565 adata->status = 0;
1566 return;
1567 }
1568
1569 // And to finish inform about MUTT_REOPEN if needed
1570 if (mdata->reopen & IMAP_EXPUNGE_PENDING && !(mdata->reopen & IMAP_EXPUNGE_EXPECTED))
1571 mdata->check_status |= IMAP_EXPUNGE_PENDING;
1572
1573 if (mdata->reopen & IMAP_EXPUNGE_PENDING)
1575 }
1576
1577 adata->status = 0;
1578}
void imap_expunge_mailbox(struct Mailbox *m, bool resort)
Purge messages from the server.
Definition imap.c:849
size_t imap_msn_highest(const struct MSNArray *msn)
Return the highest MSN in use.
Definition msn.c:72
bool closing
If true, we are waiting for CLOSE completion.
Definition adata.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_code()

bool imap_code ( const char * s)

Was the command successful.

Parameters
sIMAP command status
Return values
1Command result was OK
0NO or BAD

Definition at line 1372 of file command.c.

1373{
1374 return cmd_status(s) == IMAP_RES_OK;
1375}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_cmd_trailer()

const char * imap_cmd_trailer ( struct ImapAccountData * adata)

Extra information after tagged command response if any.

Parameters
adataImap Account data
Return values
ptrExtra command information (pointer into adata->buf)
""Error (static string)

Definition at line 1383 of file command.c.

1384{
1385 static const char *notrailer = "";
1386 const char *s = adata->buf;
1387
1388 if (!s)
1389 {
1390 mutt_debug(LL_DEBUG2, "not a tagged response\n");
1391 return notrailer;
1392 }
1393
1394 s = imap_next_word((char *) s);
1395 if (!s || (!mutt_istr_startswith(s, "OK") && !mutt_istr_startswith(s, "NO") &&
1396 !mutt_istr_startswith(s, "BAD")))
1397 {
1398 mutt_debug(LL_DEBUG2, "not a command completion: %s\n", adata->buf);
1399 return notrailer;
1400 }
1401
1402 s = imap_next_word((char *) s);
1403 if (!s)
1404 return notrailer;
1405
1406 return s;
1407}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_exec()

int imap_exec ( struct ImapAccountData * adata,
const char * cmdstr,
ImapCmdFlags flags )

Execute a command and wait for the response from the server.

Parameters
adataImap Account data
cmdstrCommand to execute
flagsFlags, see ImapCmdFlags
Return values
IMAP_EXEC_SUCCESSCommand successful or queued
IMAP_EXEC_ERRORCommand returned an error
IMAP_EXEC_FATALImap connection failure

Also, handle untagged responses.

Definition at line 1420 of file command.c.

1421{
1422 if (!adata)
1423 return IMAP_EXEC_ERROR;
1424
1425 /* Check connection health before executing command */
1426 if ((adata->state >= IMAP_AUTHENTICATED) && (adata->last_success > 0))
1427 {
1428 time_t now = mutt_date_now();
1429 time_t idle_time = now - adata->last_success;
1430
1431 if (idle_time > IMAP_CONN_STALE_THRESHOLD)
1432 {
1433 static bool probing = false;
1434 if (!probing)
1435 {
1436 mutt_debug(LL_DEBUG2, "Connection idle for %ld seconds, sending NOOP probe\n",
1437 (long) idle_time);
1438 probing = true;
1439 int noop_rc = imap_exec(adata, "NOOP", IMAP_CMD_POLL);
1440 probing = false;
1441 if (noop_rc == IMAP_EXEC_FATAL)
1442 return IMAP_EXEC_FATAL;
1443 }
1444 }
1445 }
1446
1447 if (flags & IMAP_CMD_SINGLE)
1448 {
1449 // Process any existing commands
1450 if (adata->nextcmd != adata->lastcmd)
1451 imap_exec(adata, NULL, IMAP_CMD_POLL);
1452 }
1453
1454 int rc = cmd_start(adata, cmdstr, flags);
1455 if (rc < 0)
1456 {
1457 cmd_handle_fatal(adata);
1458 return IMAP_EXEC_FATAL;
1459 }
1460
1461 if (flags & IMAP_CMD_QUEUE)
1462 return IMAP_EXEC_SUCCESS;
1463
1464 const short c_imap_poll_timeout = cs_subset_number(NeoMutt->sub, "imap_poll_timeout");
1465 if ((flags & IMAP_CMD_POLL) && (c_imap_poll_timeout > 0) &&
1466 ((mutt_socket_poll(adata->conn, c_imap_poll_timeout)) == 0))
1467 {
1468 mutt_error(_("Connection to %s timed out"), adata->conn->account.host);
1469 cmd_handle_fatal(adata);
1470 return IMAP_EXEC_FATAL;
1471 }
1472
1473 /* Allow interruptions, particularly useful if there are network problems. */
1475 do
1476 {
1477 rc = imap_cmd_step(adata);
1478 // The queue is empty, so the single command has been processed
1479 if ((flags & IMAP_CMD_SINGLE) && (adata->nextcmd == adata->lastcmd))
1480 break;
1481 } while (rc == IMAP_RES_CONTINUE);
1483
1484 if (rc == IMAP_RES_NO)
1485 return IMAP_EXEC_ERROR;
1486 if (rc != IMAP_RES_OK)
1487 {
1488 if (adata->status != IMAP_FATAL)
1489 return IMAP_EXEC_ERROR;
1490
1491 mutt_debug(LL_DEBUG1, "command failed: %s\n", adata->buf);
1492 return IMAP_EXEC_FATAL;
1493 }
1494
1495 /* Track successful command completion for connection health monitoring */
1496 adata->last_success = mutt_date_now();
1497
1498 return IMAP_EXEC_SUCCESS;
1499}
#define IMAP_CONN_STALE_THRESHOLD
Threshold in seconds after which to consider a connection potentially stale.
Definition command.c:72
void mutt_sig_allow_interrupt(bool allow)
Allow/disallow Ctrl-C (SIGINT)
Definition signal.c:315
int mutt_socket_poll(struct Connection *conn, time_t wait_secs)
Checks whether reads would block.
Definition socket.c:182
time_t last_success
last time a command completed successfully
Definition adata.h:60
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_cmd_idle()

int imap_cmd_idle ( struct ImapAccountData * adata)

Enter the IDLE state.

Parameters
adataImap Account data
Return values
0Success
<0Failure, e.g. IMAP_RES_BAD

Definition at line 1586 of file command.c.

1587{
1588 int rc;
1589
1590 mutt_debug(LL_DEBUG2, "Entering IDLE mode for %s\n",
1591 adata->conn ? adata->conn->account.host : "NULL");
1592
1593 if (cmd_start(adata, "IDLE", IMAP_CMD_POLL) < 0)
1594 {
1595 mutt_debug(LL_DEBUG1, "Failed to send IDLE command\n");
1596 cmd_handle_fatal(adata);
1597 return -1;
1598 }
1599
1600 const short c_imap_poll_timeout = cs_subset_number(NeoMutt->sub, "imap_poll_timeout");
1601 mutt_debug(LL_DEBUG2, "Waiting for IDLE continuation (timeout=%d)\n", c_imap_poll_timeout);
1602
1603 if ((c_imap_poll_timeout > 0) &&
1604 ((mutt_socket_poll(adata->conn, c_imap_poll_timeout)) == 0))
1605 {
1606 mutt_debug(LL_DEBUG1, "IDLE timed out waiting for server continuation response\n");
1607 mutt_error(_("Connection to %s timed out waiting for IDLE response"),
1608 adata->conn->account.host);
1609 cmd_handle_fatal(adata);
1610 return -1;
1611 }
1612
1613 do
1614 {
1615 rc = imap_cmd_step(adata);
1616 } while (rc == IMAP_RES_CONTINUE);
1617
1618 if (rc == IMAP_RES_RESPOND)
1619 {
1620 /* successfully entered IDLE state */
1621 adata->state = IMAP_IDLE;
1622 /* queue automatic exit when next command is issued */
1623 buf_addstr(&adata->cmdbuf, "DONE\r\n");
1624 mutt_debug(LL_DEBUG2, "Successfully entered IDLE state\n");
1625 rc = IMAP_RES_OK;
1626 }
1627 if (rc != IMAP_RES_OK)
1628 {
1629 mutt_debug(LL_DEBUG1, "IDLE command failed with rc=%d (expected RESPOND=%d)\n",
1630 rc, IMAP_RES_RESPOND);
1631 mutt_error(_("IDLE command failed for %s"), adata->conn->account.host);
1632 return -1;
1633 }
1634
1635 return 0;
1636}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_read_headers()

int imap_read_headers ( struct Mailbox * m,
unsigned int msn_begin,
unsigned int msn_end,
bool initial_download )

Read headers from the server.

Parameters
mImap Selected Mailbox
msn_beginFirst Message Sequence Number
msn_endLast Message Sequence Number
initial_downloadtrue, if this is the first opening of the mailbox
Return values
numLast MSN
-1Failure

Changed to read many headers instead of just one. It will return the msn of the last message read. It will return a value other than msn_end if mail comes in while downloading headers (in theory).

Definition at line 1366 of file message.c.

1368{
1369 unsigned int maxuid = 0;
1370 int rc = -1;
1371 bool evalhc = false;
1372
1373#ifdef USE_HCACHE
1374 uint32_t uidvalidity = 0;
1375 unsigned int uid_next = 0;
1376 unsigned long long modseq = 0;
1377 bool has_condstore = false;
1378 bool has_qresync = false;
1379 bool eval_condstore = false;
1380 bool eval_qresync = false;
1381 char *uid_seqset = NULL;
1382 const unsigned int msn_begin_save = msn_begin;
1383#endif /* USE_HCACHE */
1384
1386 struct ImapMboxData *mdata = imap_mdata_get(m);
1387 if (!adata || (adata->mailbox != m) || !mdata)
1388 return -1;
1389
1390#ifdef USE_HCACHE
1391retry:
1392#endif /* USE_HCACHE */
1393
1394 /* make sure context has room to hold the mailbox */
1395 mx_alloc_memory(m, msn_end);
1396 imap_msn_reserve(&mdata->msn, msn_end);
1397 imap_alloc_uid_hash(adata, m, msn_end);
1398
1400 mdata->new_mail_count = 0;
1401
1402#ifdef USE_HCACHE
1403 imap_hcache_open(adata, mdata, true);
1404
1405 if (mdata->hcache && initial_download)
1406 {
1407 hcache_fetch_raw_obj(mdata->hcache, "UIDVALIDITY", 11, &uidvalidity);
1408 hcache_fetch_raw_obj(mdata->hcache, "UIDNEXT", 7, &uid_next);
1409 if (mdata->modseq)
1410 {
1411 const bool c_imap_condstore = cs_subset_bool(NeoMutt->sub, "imap_condstore");
1412 if ((adata->capabilities & IMAP_CAP_CONDSTORE) && c_imap_condstore)
1413 has_condstore = true;
1414
1415 /* If IMAP_CAP_QRESYNC and ImapQResync then NeoMutt sends ENABLE QRESYNC.
1416 * If we receive an ENABLED response back, then adata->qresync is set. */
1417 if (adata->qresync)
1418 has_qresync = true;
1419 }
1420
1421 if (uidvalidity && uid_next && (uidvalidity == mdata->uidvalidity))
1422 {
1423 evalhc = true;
1424 if (hcache_fetch_raw_obj(mdata->hcache, "MODSEQ", 6, &modseq))
1425 {
1426 if (has_qresync)
1427 {
1428 uid_seqset = imap_hcache_get_uid_seqset(mdata);
1429 if (uid_seqset)
1430 eval_qresync = true;
1431 }
1432
1433 if (!eval_qresync && has_condstore)
1434 eval_condstore = true;
1435 }
1436 }
1437 }
1438 if (evalhc)
1439 {
1440 if (eval_qresync)
1441 {
1442 if (read_headers_qresync_eval_cache(adata, m, uid_seqset) < 0)
1443 goto bail;
1444 }
1445 else
1446 {
1447 if (read_headers_normal_eval_cache(adata, m, msn_end, uid_next,
1448 has_condstore || has_qresync, eval_condstore) < 0)
1449 goto bail;
1450 }
1451
1452 if ((eval_condstore || eval_qresync) && (modseq != mdata->modseq))
1453 {
1454 if (read_headers_condstore_qresync_updates(adata, m, msn_end, uid_next,
1455 modseq, eval_qresync) < 0)
1456 {
1457 goto bail;
1458 }
1459 }
1460
1461 /* Look for the first empty MSN and start there */
1462 while (msn_begin <= msn_end)
1463 {
1464 if (!imap_msn_get(&mdata->msn, msn_begin - 1))
1465 break;
1466 msn_begin++;
1467 }
1468 }
1469#endif /* USE_HCACHE */
1470
1471 if (read_headers_fetch_new(m, msn_begin, msn_end, evalhc, &maxuid, initial_download) < 0)
1472 goto bail;
1473
1474#ifdef USE_HCACHE
1475 if (eval_qresync && initial_download)
1476 {
1477 if (imap_verify_qresync(m) != 0)
1478 {
1479 eval_qresync = false;
1480 eval_condstore = false;
1481 evalhc = false;
1482 modseq = 0;
1483 maxuid = 0;
1484 FREE(&uid_seqset);
1485 uidvalidity = 0;
1486 uid_next = 0;
1487 msn_begin = msn_begin_save;
1488
1489 goto retry;
1490 }
1491 }
1492#endif /* USE_HCACHE */
1493
1494 if (maxuid && (mdata->uid_next < maxuid + 1))
1495 mdata->uid_next = maxuid + 1;
1496
1497#ifdef USE_HCACHE
1498 hcache_store_raw(mdata->hcache, "UIDVALIDITY", 11, &mdata->uidvalidity,
1499 sizeof(mdata->uidvalidity));
1500 if (maxuid && (mdata->uid_next < maxuid + 1))
1501 {
1502 mutt_debug(LL_DEBUG2, "Overriding UIDNEXT: %u -> %u\n", mdata->uid_next, maxuid + 1);
1503 mdata->uid_next = maxuid + 1;
1504 }
1505 if (mdata->uid_next > 1)
1506 {
1507 hcache_store_raw(mdata->hcache, "UIDNEXT", 7, &mdata->uid_next, sizeof(mdata->uid_next));
1508 }
1509
1510 /* We currently only sync CONDSTORE and QRESYNC on the initial download.
1511 * To do it more often, we'll need to deal with flag updates combined with
1512 * unsync'ed local flag changes. We'll also need to properly sync flags to
1513 * the header cache on close. I'm not sure it's worth the added complexity. */
1514 if (initial_download)
1515 {
1516 if (has_condstore || has_qresync)
1517 {
1518 hcache_store_raw(mdata->hcache, "MODSEQ", 6, &mdata->modseq, sizeof(mdata->modseq));
1519 }
1520 else
1521 {
1522 hcache_delete_raw(mdata->hcache, "MODSEQ", 6);
1523 }
1524
1525 if (has_qresync)
1527 else
1529 }
1530#endif /* USE_HCACHE */
1531
1532 /* TODO: it's not clear to me why we are calling mx_alloc_memory yet again. */
1534
1535 mdata->reopen |= IMAP_REOPEN_ALLOW;
1536
1537 rc = msn_end;
1538
1539bail:
1540#ifdef USE_HCACHE
1542 FREE(&uid_seqset);
1543#endif /* USE_HCACHE */
1544
1545 return rc;
1546}
int hcache_delete_raw(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition hcache.c:765
int hcache_store_raw(struct HeaderCache *hc, const char *key, size_t keylen, void *data, size_t dlen)
Store a key / data pair.
Definition hcache.c:737
#define hcache_fetch_raw_obj(hc, key, keylen, dst)
Definition lib.h:168
static int read_headers_normal_eval_cache(struct ImapAccountData *adata, struct Mailbox *m, unsigned int msn_end, unsigned int uid_next, bool store_flag_updates, bool eval_condstore)
Retrieve data from the header cache.
Definition message.c:697
static int imap_verify_qresync(struct Mailbox *m)
Check to see if QRESYNC got jumbled.
Definition message.c:1038
static int read_headers_condstore_qresync_updates(struct ImapAccountData *adata, struct Mailbox *m, unsigned int msn_end, unsigned int uid_next, unsigned long long hc_modseq, bool eval_qresync)
Retrieve updates from the server.
Definition message.c:936
static void imap_alloc_uid_hash(struct ImapAccountData *adata, struct Mailbox *m, unsigned int msn_count)
Create a Hash Table for the UIDs.
Definition message.c:534
static int read_headers_qresync_eval_cache(struct ImapAccountData *adata, struct Mailbox *m, char *uid_seqset)
Retrieve data from the header cache.
Definition message.c:847
static int read_headers_fetch_new(struct Mailbox *m, unsigned int msn_begin, unsigned int msn_end, bool evalhc, unsigned int *maxuid, bool initial_download)
Retrieve new messages from the server.
Definition message.c:1115
int imap_hcache_store_uid_seqset(struct ImapMboxData *mdata)
Store a UID Sequence Set in the header cache.
Definition util.c:423
char * imap_hcache_get_uid_seqset(struct ImapMboxData *mdata)
Get a UID Sequence Set from the header cache.
Definition util.c:458
int imap_hcache_clear_uid_seqset(struct ImapMboxData *mdata)
Delete a UID Sequence Set from the header cache.
Definition util.c:444
struct Email * imap_msn_get(const struct MSNArray *msn, int idx)
Return the Email associated with an msn.
Definition msn.c:83
void imap_msn_reserve(struct MSNArray *msn, size_t num)
Create / reallocate the cache.
Definition msn.c:44
bool qresync
true, if QRESYNC is successfully ENABLE'd
Definition adata.h:65
unsigned int uid_next
Next UID for new message.
Definition mdata.h:52
unsigned long long modseq
Modification sequence number.
Definition mdata.h:53
uint32_t uidvalidity
UID validity.
Definition mdata.h:51
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_set_flags()

char * imap_set_flags ( struct Mailbox * m,
struct Email * e,
char * s,
bool * server_changes )

Fill the message header according to the server flags.

Parameters
[in]mImap Selected Mailbox
[in]eEmail
[in]sCommand string
[out]server_changesSet to true if the flags have changed
Return values
ptrThe end of flags string
NULLFailure

Expects a flags line of the form "FLAGS (flag flag ...)"

imap_set_flags: fill out the message header according to the flags from the server. Expects a flags line of the form "FLAGS (flag flag ...)"

Sets server_changes to 1 if a change to a flag is made, or in the case of e->changed, if a change to a flag would have been made.

Definition at line 1952 of file message.c.

1953{
1955 if (!adata || (adata->mailbox != m))
1956 return NULL;
1957
1958 struct ImapHeader newh = { 0 };
1959 struct ImapEmailData old_edata = { 0 };
1960 int local_changes = e->changed;
1961
1962 struct ImapEmailData *edata = e->edata;
1963 newh.edata = edata;
1964
1965 mutt_debug(LL_DEBUG2, "parsing FLAGS\n");
1966 s = msg_parse_flags(&newh, s);
1967 if (!s)
1968 return NULL;
1969
1970 /* Update tags system */
1971 /* We take a copy of the tags so we can split the string */
1972 char *tags_copy = mutt_str_dup(edata->flags_remote);
1973 driver_tags_replace(&e->tags, tags_copy);
1974 FREE(&tags_copy);
1975
1976 /* YAUH (yet another ugly hack): temporarily set context to
1977 * read-write even if it's read-only, so *server* updates of
1978 * flags can be processed by mutt_set_flag. mailbox->changed must
1979 * be restored afterwards */
1980 bool readonly = m->readonly;
1981 m->readonly = false;
1982
1983 /* This is redundant with the following two checks. Removing:
1984 * mutt_set_flag (m, e, MUTT_NEW, !(edata->read || edata->old), true); */
1985 set_changed_flag(m, e, local_changes, server_changes, MUTT_OLD, old_edata.old,
1986 edata->old, e->old);
1987 set_changed_flag(m, e, local_changes, server_changes, MUTT_READ,
1988 old_edata.read, edata->read, e->read);
1989 set_changed_flag(m, e, local_changes, server_changes, MUTT_DELETE,
1990 old_edata.deleted, edata->deleted, e->deleted);
1991 set_changed_flag(m, e, local_changes, server_changes, MUTT_FLAG,
1992 old_edata.flagged, edata->flagged, e->flagged);
1993 set_changed_flag(m, e, local_changes, server_changes, MUTT_REPLIED,
1994 old_edata.replied, edata->replied, e->replied);
1995
1996 /* this message is now definitively *not* changed (mutt_set_flag
1997 * marks things changed as a side-effect) */
1998 if (local_changes == 0)
1999 e->changed = false;
2000 m->changed &= !readonly;
2001 m->readonly = readonly;
2002
2003 return s;
2004}
static void set_changed_flag(struct Mailbox *m, struct Email *e, int local_changes, bool *server_changes, enum MessageType flag_name, bool old_hd_flag, bool new_hd_flag, bool h_flag)
Have the flags of an email changed.
Definition message.c:656
static char * msg_parse_flags(struct ImapHeader *h, char *s)
Read a FLAGS token into an ImapHeader.
Definition message.c:194
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
@ MUTT_READ
Messages that have been read.
Definition mutt.h:92
@ MUTT_OLD
Old messages.
Definition mutt.h:90
@ MUTT_FLAG
Flagged messages.
Definition mutt.h:98
@ MUTT_DELETE
Messages to be deleted.
Definition mutt.h:94
@ MUTT_REPLIED
Messages that have been replied to.
Definition mutt.h:91
bool old
Email has been seen.
Definition edata.h:38
bool read
Email has been read.
Definition edata.h:37
bool flagged
Email has been flagged.
Definition edata.h:40
bool replied
Email has been replied to.
Definition edata.h:41
IMAP-specific header.
Definition message.h:34
struct ImapEmailData * edata
IMAP-specific Email data.
Definition message.h:35
bool changed
Mailbox has been modified.
Definition mailbox.h:112
bool readonly
Don't allow changes to the mailbox.
Definition mailbox.h:118
bool driver_tags_replace(struct TagList *tl, const char *tags)
Replace all tags.
Definition tags.c:202
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_cache_del()

int imap_cache_del ( struct Mailbox * m,
struct Email * e )

Delete an email from the body cache.

Parameters
mSelected Imap Mailbox
eEmail
Return values
0Success
-1Failure

Definition at line 1901 of file message.c.

1902{
1904 struct ImapMboxData *mdata = imap_mdata_get(m);
1905
1906 if (!e || !adata || (adata->mailbox != m) || !mdata)
1907 return -1;
1908
1909 mdata->bcache = imap_bcache_open(m);
1910 char id[64] = { 0 };
1911 snprintf(id, sizeof(id), "%u-%u", mdata->uidvalidity, imap_edata_get(e)->uid);
1912 return mutt_bcache_del(mdata->bcache, id);
1913}
int mutt_bcache_del(struct BodyCache *bcache, const char *id)
Delete a file from the Body Cache.
Definition bcache.c:274
static struct BodyCache * imap_bcache_open(struct Mailbox *m)
Open a message cache.
Definition message.c:81
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_cache_clean()

int imap_cache_clean ( struct Mailbox * m)

Delete all the entries in the message cache.

Parameters
mSelectedImap Mailbox
Return values
0Always

Definition at line 1920 of file message.c.

1921{
1923 struct ImapMboxData *mdata = imap_mdata_get(m);
1924
1925 if (!adata || (adata->mailbox != m) || !mdata)
1926 return -1;
1927
1928 mdata->bcache = imap_bcache_open(m);
1930
1931 return 0;
1932}
int mutt_bcache_list(struct BodyCache *bcache, bcache_list_t want_id, void *data)
Find matching entries in the Body Cache.
Definition bcache.c:339
static int imap_bcache_delete(const char *id, struct BodyCache *bcache, void *data)
Delete an entry from the message cache - Implements bcache_list_t -.
Definition message.c:169
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_append_message()

int imap_append_message ( struct Mailbox * m,
struct Message * msg )

Write an email back to the server.

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

Definition at line 1555 of file message.c.

1556{
1557 if (!m || !msg)
1558 return -1;
1559
1561 struct ImapMboxData *mdata = imap_mdata_get(m);
1562 if (!adata || !mdata)
1563 return -1;
1564
1565 FILE *fp = NULL;
1566 char buf[2048] = { 0 };
1567 struct Buffer *internaldate = NULL;
1568 struct Buffer *imap_flags = NULL;
1569 size_t len;
1570 struct Progress *progress = NULL;
1571 size_t sent;
1572 int c, last;
1573 int rc;
1574
1575 fp = mutt_file_fopen(msg->path, "r");
1576 if (!fp)
1577 {
1578 mutt_perror("%s", msg->path);
1579 goto fail;
1580 }
1581
1582 /* currently we set the \Seen flag on all messages, but probably we
1583 * should scan the message Status header for flag info. Since we're
1584 * already rereading the whole file for length it isn't any more
1585 * expensive (it'd be nice if we had the file size passed in already
1586 * by the code that writes the file, but that's a lot of changes.
1587 * Ideally we'd have an Email structure with flag info here... */
1588 for (last = EOF, len = 0; (c = fgetc(fp)) != EOF; last = c)
1589 {
1590 if ((c == '\n') && (last != '\r'))
1591 len++;
1592
1593 len++;
1594 }
1595 rewind(fp);
1596
1597 if (m->verbose)
1598 {
1600 progress = progress_new(MUTT_PROGRESS_NET, len);
1601 progress_set_message(progress, _("Uploading message..."));
1602 }
1603
1604 internaldate = buf_pool_get();
1605 mutt_date_make_imap(internaldate, msg->received);
1606
1607 imap_flags = buf_pool_get();
1608
1609 if (msg->flags.read)
1610 buf_addstr(imap_flags, " \\Seen");
1611 if (msg->flags.replied)
1612 buf_addstr(imap_flags, " \\Answered");
1613 if (msg->flags.flagged)
1614 buf_addstr(imap_flags, " \\Flagged");
1615 if (msg->flags.draft)
1616 buf_addstr(imap_flags, " \\Draft");
1617
1618 snprintf(buf, sizeof(buf), "APPEND %s (%s) \"%s\" {%lu}", mdata->munge_name,
1619 imap_flags->data + 1, buf_string(internaldate), (unsigned long) len);
1620 buf_pool_release(&internaldate);
1621
1622 imap_cmd_start(adata, buf);
1623
1624 do
1625 {
1626 rc = imap_cmd_step(adata);
1627 } while (rc == IMAP_RES_CONTINUE);
1628
1629 if (rc != IMAP_RES_RESPOND)
1630 goto cmd_step_fail;
1631
1632 for (last = EOF, sent = len = 0; (c = fgetc(fp)) != EOF; last = c)
1633 {
1634 if ((c == '\n') && (last != '\r'))
1635 buf[len++] = '\r';
1636
1637 buf[len++] = c;
1638
1639 if (len > sizeof(buf) - 3)
1640 {
1641 sent += len;
1642 if (flush_buffer(buf, &len, adata->conn) < 0)
1643 goto fail;
1644 progress_update(progress, sent, -1);
1645 }
1646 }
1647
1648 if (len > 0)
1649 if (flush_buffer(buf, &len, adata->conn) < 0)
1650 goto fail;
1651
1652 if (mutt_socket_send(adata->conn, "\r\n") < 0)
1653 goto fail;
1654 mutt_file_fclose(&fp);
1655
1656 do
1657 {
1658 rc = imap_cmd_step(adata);
1659 } while (rc == IMAP_RES_CONTINUE);
1660
1661 if (rc != IMAP_RES_OK)
1662 goto cmd_step_fail;
1663
1664 progress_free(&progress);
1665 buf_pool_release(&imap_flags);
1666 return 0;
1667
1668cmd_step_fail:
1669 mutt_debug(LL_DEBUG1, "command failed: %s\n", adata->buf);
1670 if (rc != IMAP_RES_BAD)
1671 {
1672 char *pc = imap_next_word(adata->buf); /* skip sequence number or token */
1673 pc = imap_next_word(pc); /* skip response code */
1674 if (*pc != '\0')
1675 mutt_error("%s", pc);
1676 }
1677
1678fail:
1679 mutt_file_fclose(&fp);
1680 progress_free(&progress);
1681 buf_pool_release(&imap_flags);
1682 return -1;
1683}
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
#define mutt_perror(...)
Definition logging2.h:95
int imap_cmd_start(struct ImapAccountData *adata, const char *cmdstr)
Given an IMAP command, send it to the server.
Definition command.c:1216
static int flush_buffer(char *buf, size_t *len, struct Connection *conn)
Write data to a connection.
Definition message.c:493
int mutt_date_make_imap(struct Buffer *buf, time_t timestamp)
Format date in IMAP style: DD-MMM-YYYY HH:MM:SS +ZZzz.
Definition date.c:812
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
@ MUTT_PROGRESS_NET
Progress tracks bytes, according to $net_inc
Definition lib.h:83
struct Progress * progress_new(enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition progress.c:139
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition progress.c:110
void progress_set_message(struct Progress *progress, const char *fmt,...) __attribute__((__format__(__printf__
#define mutt_socket_send(conn, buf)
Definition socket.h:56
char * munge_name
Munged version of the mailbox name.
Definition mdata.h:42
bool verbose
Display status messages?
Definition mailbox.h:119
char * path
path to temp file
Definition message.h:36
struct Message::@264267271004327071125374067057142037276212342100 flags
Flags for the Message.
bool draft
Message has been read.
Definition message.h:44
bool replied
Message has been replied to.
Definition message.h:43
time_t received
Time at which this message was received.
Definition message.h:46
bool flagged
Message is flagged.
Definition message.h:42
bool read
Message has been read.
Definition message.h:41
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_hcache_open()

void imap_hcache_open ( struct ImapAccountData * adata,
struct ImapMboxData * mdata,
bool create )

Open a header cache.

Parameters
adataImap Account data
mdataImap Mailbox data
createCreate a new header cache if missing?

Definition at line 307 of file util.c.

308{
309 if (!adata || !mdata)
310 return;
311
312 if (mdata->hcache)
313 return;
314
315 struct HeaderCache *hc = NULL;
316 struct Buffer *mbox = buf_pool_get();
317 struct Buffer *cachepath = buf_pool_get();
318
319 imap_cachepath(adata->delim, mdata->name, mbox);
320
321 if (strstr(buf_string(mbox), "/../") || mutt_str_equal(buf_string(mbox), "..") ||
322 mutt_strn_equal(buf_string(mbox), "../", 3))
323 {
324 goto cleanup;
325 }
326 size_t len = buf_len(mbox);
327 if ((len > 3) && (mutt_str_equal(buf_string(mbox) + len - 3, "/..")))
328 goto cleanup;
329
330 struct Url url = { 0 };
331 account_to_url(&adata->conn->account, &url);
332 url.path = mbox->data;
333 url_tobuffer(&url, cachepath, U_PATH);
334
335 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
336 hc = hcache_open(c_header_cache, buf_string(cachepath), imap_hcache_namer, create);
337
338cleanup:
339 buf_pool_release(&mbox);
340 buf_pool_release(&cachepath);
341 mdata->hcache = hc;
342}
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:491
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
static void imap_hcache_namer(const struct StoreOps *store_ops, const char *path, struct Buffer *dest)
Generate a filename for the header cache - Implements hcache_namer_t -.
Definition util.c:295
struct HeaderCache * hcache_open(const char *path, const char *folder, hcache_namer_t namer, bool create)
Multiplexor for StoreOps::open.
Definition hcache.c:477
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition string.c:429
void account_to_url(struct ConnAccount *cac, struct Url *url)
Fill URL with info from account.
Header Cache.
Definition lib.h:87
struct HeaderCache * hcache
Email header cache.
Definition mdata.h:64
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition url.h:69
char * path
Path.
Definition url.h:75
int url_tobuffer(const struct Url *url, struct Buffer *buf, uint8_t flags)
Output the URL string for a given Url object.
Definition url.c:361
#define U_PATH
Path is included in URL.
Definition url.h:50
void imap_cachepath(char delim, const char *mailbox, struct Buffer *dest)
Generate a cache path for a mailbox.
Definition util.c:754
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_hcache_close()

void imap_hcache_close ( struct ImapMboxData * mdata)

Close the header cache.

Parameters
mdataImap Mailbox data

Definition at line 348 of file util.c.

349{
350 if (!mdata->hcache)
351 return;
352
353 hcache_close(&mdata->hcache);
354}
void hcache_close(struct HeaderCache **ptr)
Multiplexor for StoreOps::close.
Definition hcache.c:549
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_hcache_get()

struct Email * imap_hcache_get ( struct ImapMboxData * mdata,
unsigned int uid )

Get a header cache entry by its UID.

Parameters
mdataImap Mailbox data
uidUID to find
Return values
ptrEmail
NULLFailure

Definition at line 363 of file util.c.

364{
365 if (!mdata->hcache)
366 return NULL;
367
368 char key[16] = { 0 };
369
370 snprintf(key, sizeof(key), "%u", uid);
371 struct HCacheEntry hce = hcache_fetch_email(mdata->hcache, key, mutt_str_len(key),
372 mdata->uidvalidity);
373 if (!hce.email && hce.uidvalidity)
374 {
375 mutt_debug(LL_DEBUG3, "hcache uidvalidity mismatch: %u\n", hce.uidvalidity);
376 }
377
378 return hce.email;
379}
struct HCacheEntry hcache_fetch_email(struct HeaderCache *hc, const char *key, size_t keylen, uint32_t uidvalidity)
Multiplexor for StoreOps::fetch.
Definition hcache.c:569
Wrapper for Email retrieved from the header cache.
Definition lib.h:100
uint32_t uidvalidity
IMAP-specific UIDVALIDITY.
Definition lib.h:101
struct Email * email
Retrieved email.
Definition lib.h:103
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_hcache_put()

int imap_hcache_put ( struct ImapMboxData * mdata,
struct Email * e )

Add an entry to the header cache.

Parameters
mdataImap Mailbox data
eEmail
Return values
0Success
-1Failure

Definition at line 388 of file util.c.

389{
390 if (!mdata->hcache)
391 return -1;
392
393 char key[16] = { 0 };
394
395 snprintf(key, sizeof(key), "%u", imap_edata_get(e)->uid);
396 return hcache_store_email(mdata->hcache, key, mutt_str_len(key), e, mdata->uidvalidity);
397}
int hcache_store_email(struct HeaderCache *hc, const char *key, size_t keylen, struct Email *e, uint32_t uidvalidity)
Multiplexor for StoreOps::store.
Definition hcache.c:683
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_hcache_del()

int imap_hcache_del ( struct ImapMboxData * mdata,
unsigned int uid )

Delete an item from the header cache.

Parameters
mdataImap Mailbox data
uidUID of entry to delete
Return values
0Success
-1Failure

Definition at line 406 of file util.c.

407{
408 if (!mdata->hcache)
409 return -1;
410
411 char key[16] = { 0 };
412
413 snprintf(key, sizeof(key), "%u", uid);
414 return hcache_delete_email(mdata->hcache, key, mutt_str_len(key));
415}
int hcache_delete_email(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition hcache.c:752
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_hcache_store_uid_seqset()

int imap_hcache_store_uid_seqset ( struct ImapMboxData * mdata)

Store a UID Sequence Set in the header cache.

Parameters
mdataImap Mailbox data
Return values
0Success
-1Error

Definition at line 423 of file util.c.

424{
425 if (!mdata->hcache)
426 return -1;
427
428 struct Buffer *buf = buf_pool_get();
429 buf_alloc(buf, 8192); // The seqset is likely large. Preallocate to reduce reallocs
431
432 int rc = hcache_store_raw(mdata->hcache, "UIDSEQSET", 9, buf->data, buf_len(buf) + 1);
433 mutt_debug(LL_DEBUG3, "Stored UIDSEQSET %s\n", buf_string(buf));
434 buf_pool_release(&buf);
435 return rc;
436}
static void imap_msn_index_to_uid_seqset(struct Buffer *buf, struct ImapMboxData *mdata)
Convert MSN index of UIDs to Seqset.
Definition util.c:238
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_hcache_clear_uid_seqset()

int imap_hcache_clear_uid_seqset ( struct ImapMboxData * mdata)

Delete a UID Sequence Set from the header cache.

Parameters
mdataImap Mailbox data
Return values
0Success
-1Error

Definition at line 444 of file util.c.

445{
446 if (!mdata->hcache)
447 return -1;
448
449 return hcache_delete_raw(mdata->hcache, "UIDSEQSET", 9);
450}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_hcache_get_uid_seqset()

char * imap_hcache_get_uid_seqset ( struct ImapMboxData * mdata)

Get a UID Sequence Set from the header cache.

Parameters
mdataImap Mailbox data
Return values
ptrUID Sequence Set
NULLError

Definition at line 458 of file util.c.

459{
460 if (!mdata->hcache)
461 return NULL;
462
463 char *seqset = hcache_fetch_raw_str(mdata->hcache, "UIDSEQSET", 9);
464 mutt_debug(LL_DEBUG3, "Retrieved UIDSEQSET %s\n", NONULL(seqset));
465
466 return seqset;
467}
char * hcache_fetch_raw_str(struct HeaderCache *hc, const char *key, size_t keylen)
Fetch a string from the cache.
Definition hcache.c:662
#define NONULL(x)
Definition string2.h:44
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_continue()

enum QuadOption imap_continue ( const char * msg,
const char * resp )

Display a message and ask the user if they want to go on.

Parameters
msgLocation of the error
respMessage for user
Return values
QuadOptionResult, e.g. MUTT_NO

Definition at line 654 of file util.c.

655{
656 imap_error(msg, resp);
657 return query_yesorno(_("Continue?"), MUTT_NO);
658}
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition quad.h:38
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition question.c:329
void imap_error(const char *where, const char *msg)
Show an error and abort.
Definition util.c:665
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_error()

void imap_error ( const char * where,
const char * msg )

Show an error and abort.

Parameters
whereLocation of the error
msgMessage for user

Definition at line 665 of file util.c.

666{
667 mutt_error("%s [%s]", where, msg);
668}
+ Here is the caller graph for this function:

◆ imap_mdata_cache_reset()

void imap_mdata_cache_reset ( struct ImapMboxData * mdata)

Release and clear cache data of ImapMboxData structure.

Parameters
mdataImap Mailbox data

Definition at line 111 of file util.c.

112{
114 mdata->reopen = IMAP_OPEN_NONE;
115 mutt_hash_free(&mdata->uid_hash);
116 imap_msn_free(&mdata->msn);
117 mutt_bcache_close(&mdata->bcache);
118}
void mutt_bcache_close(struct BodyCache **ptr)
Close an Email-Body Cache.
Definition bcache.c:167
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition hash.c:459
void imap_msn_free(struct MSNArray *msn)
Free the cache.
Definition msn.c:62
struct BodyCache * bcache
Email body cache.
Definition mdata.h:62
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_fix_path()

char * imap_fix_path ( const char * mailbox,
char * path,
size_t plen )

Fix up the imap path.

Parameters
mailboxMailbox path
pathBuffer for the result
plenLength of buffer
Return values
ptrFixed-up path
Note
the first character in mailbox matching any of the characters in $imap_delim_chars is used as a delimiter.

This is necessary because the rest of neomutt assumes a hierarchy delimiter of '/', which is not necessarily true in IMAP. Additionally, the filesystem converts multiple hierarchy delimiters into a single one, ie "///" is equal to "/". IMAP servers are not required to do this. Moreover, IMAP servers may dislike the path ending with the delimiter.

Definition at line 686 of file util.c.

687{
688 const char *const c_imap_delim_chars = cs_subset_string(NeoMutt->sub, "imap_delim_chars");
689
690 char *out = path;
691 size_t space_left = plen - 1;
692
693 if (mailbox)
694 {
695 for (const char *c = mailbox; *c && space_left; c++, space_left--)
696 {
697 if (strchr(NONULL(c_imap_delim_chars), *c))
698 {
699 return imap_fix_path_with_delim(*c, mailbox, path, plen);
700 }
701 *out++ = *c;
702 }
703 }
704
705 *out = '\0';
706 return path;
707}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
char * imap_fix_path_with_delim(const char delim, const char *mailbox, char *path, size_t plen)
Fix up the imap path.
Definition util.c:718
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_fix_path_with_delim()

char * imap_fix_path_with_delim ( const char delim,
const char * mailbox,
char * path,
size_t plen )

Fix up the imap path.

Parameters
delimDelimiter specified by the server
mailboxMailbox path
pathBuffer for the result
plenLength of buffer
Return values
ptrFixed-up path

Definition at line 718 of file util.c.

719{
720 char *out = path;
721 size_t space_left = plen - 1;
722
723 if (mailbox)
724 {
725 for (const char *c = mailbox; *c && space_left; c++, space_left--)
726 {
727 if (*c == delim || *c == '/')
728 {
729 while (*c && *(c + 1) == *c)
730 c++;
731 *out++ = delim;
732 }
733 else
734 {
735 *out++ = *c;
736 }
737 }
738 }
739
740 if (out != path && *(out - 1) == delim)
741 {
742 out--;
743 }
744 *out = '\0';
745 return path;
746}
+ Here is the caller graph for this function:

◆ imap_cachepath()

void imap_cachepath ( char delim,
const char * mailbox,
struct Buffer * dest )

Generate a cache path for a mailbox.

Parameters
delimImap server delimiter
mailboxMailbox name
destBuffer to store cache path

Definition at line 754 of file util.c.

755{
756 const char *p = mailbox;
757 buf_reset(dest);
758 if (!p)
759 return;
760
761 while (*p)
762 {
763 if (p[0] == delim)
764 {
765 buf_addch(dest, '/');
766 /* simple way to avoid collisions with UIDs */
767 if ((p[1] >= '0') && (p[1] <= '9'))
768 buf_addch(dest, '_');
769 }
770 else
771 {
772 buf_addch(dest, *p);
773 }
774 p++;
775 }
776}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_get_literal_count()

int imap_get_literal_count ( char * buf,
unsigned int * bytes )

Write number of bytes in an IMAP literal into bytes.

Parameters
[in]bufNumber as a string
[out]bytesResulting number
Return values
0Success
-1Failure

Definition at line 785 of file util.c.

786{
787 char *pc = NULL;
788 char *pn = NULL;
789
790 if (!buf || !(pc = strchr(buf, '{')))
791 return -1;
792
793 pc++;
794 pn = pc;
795 while (mutt_isdigit(*pc))
796 pc++;
797 *pc = '\0';
798 if (!mutt_str_atoui(pn, bytes))
799 return -1;
800
801 return 0;
802}
const char * mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition atoi.c:217
bool mutt_isdigit(int arg)
Wrapper for isdigit(3)
Definition ctype.c:66
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_get_qualifier()

char * imap_get_qualifier ( char * buf)

Get the qualifier from a tagged response.

Parameters
bufCommand string to process
Return values
ptrStart of the qualifier

In a tagged response, skip tag and status for the qualifier message. Used by imap_copy_message for TRYCREATE

Definition at line 812 of file util.c.

813{
814 char *s = buf;
815
816 /* skip tag */
817 s = imap_next_word(s);
818 /* skip OK/NO/BAD response */
819 s = imap_next_word(s);
820
821 return s;
822}
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition util.c:829
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_next_word()

char * imap_next_word ( char * s)

Find where the next IMAP word begins.

Parameters
sCommand string to process
Return values
ptrNext IMAP word

Definition at line 829 of file util.c.

830{
831 bool quoted = false;
832
833 while (*s)
834 {
835 if (*s == '\\')
836 {
837 s++;
838 if (*s)
839 s++;
840 continue;
841 }
842 if (*s == '\"')
843 quoted = !quoted;
844 if (!quoted && mutt_isspace(*s))
845 break;
846 s++;
847 }
848
849 SKIPWS(s);
850 return s;
851}
bool mutt_isspace(int arg)
Wrapper for isspace(3)
Definition ctype.c:96
#define SKIPWS(ch)
Definition string2.h:52
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_qualify_path()

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

Make an absolute IMAP folder target.

Parameters
bufBuffer for the result
buflenLength of buffer
cacConnAccount of the account
pathPath relative to the mailbox

Definition at line 860 of file util.c.

861{
862 struct Url url = { 0 };
863 account_to_url(cac, &url);
864 url.path = path;
865 url_tostring(&url, buf, buflen, U_NONE);
866}
int url_tostring(const struct Url *url, char *dest, size_t len, uint8_t flags)
Output the URL string for a given Url object.
Definition url.c:426
#define U_NONE
No flags are set for URL parsing.
Definition url.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_buf_qualify_path()

void imap_buf_qualify_path ( struct Buffer * buf,
struct ConnAccount * cac,
char * path )

Make an absolute IMAP folder target to a buffer.

Parameters
bufBuffer for the result
cacConnAccount of the account
pathPath relative to the mailbox

Definition at line 874 of file util.c.

875{
876 struct Url url = { 0 };
877 account_to_url(cac, &url);
878 url.path = path;
879 url_tobuffer(&url, buf, U_NONE);
880}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_quote_string()

void imap_quote_string ( char * dest,
size_t dlen,
const char * src,
bool quote_backtick )

Quote string according to IMAP rules.

Parameters
destBuffer for the result
dlenLength of the buffer
srcString to be quoted
quote_backtickIf true, quote backticks too

Surround string with quotes, escape " and \ with backslash

Definition at line 891 of file util.c.

892{
893 const char *quote = "`\"\\";
894 if (!quote_backtick)
895 quote++;
896
897 char *pt = dest;
898 const char *s = src;
899
900 if (dlen < 3)
901 {
902 *dest = '\0';
903 return;
904 }
905
906 *pt++ = '"';
907 /* save room for quote-chars */
908 dlen -= 3;
909
910 for (; *s && dlen; s++)
911 {
912 if (strchr(quote, *s))
913 {
914 if (dlen < 2)
915 break;
916 dlen -= 2;
917 *pt++ = '\\';
918 *pt++ = *s;
919 }
920 else
921 {
922 *pt++ = *s;
923 dlen--;
924 }
925 }
926 *pt++ = '"';
927 *pt = '\0';
928}
+ Here is the caller graph for this function:

◆ imap_unquote_string()

void imap_unquote_string ( char * s)

Equally stupid unquoting routine.

Parameters
sString to be unquoted

Definition at line 934 of file util.c.

935{
936 char *d = s;
937
938 if (*s == '\"')
939 s++;
940 else
941 return;
942
943 while (*s)
944 {
945 if (*s == '\"')
946 {
947 *d = '\0';
948 return;
949 }
950 if (*s == '\\')
951 {
952 s++;
953 }
954 if (*s)
955 {
956 *d = *s;
957 d++;
958 s++;
959 }
960 }
961 *d = '\0';
962}
+ Here is the caller graph for this function:

◆ imap_munge_mbox_name()

void imap_munge_mbox_name ( bool unicode,
char * dest,
size_t dlen,
const char * src )

Quote awkward characters in a mailbox name.

Parameters
unicodetrue if Unicode is allowed
destBuffer to store safe mailbox name
dlenLength of buffer
srcMailbox name

Definition at line 971 of file util.c.

972{
973 char *buf = mutt_str_dup(src);
974 imap_utf_encode(unicode, &buf);
975
976 imap_quote_string(dest, dlen, buf, false);
977
978 FREE(&buf);
979}
void imap_utf_encode(bool unicode, char **s)
Encode email from local charset to UTF-8.
Definition utf7.c:397
void imap_quote_string(char *dest, size_t dlen, const char *src, bool quote_backtick)
Quote string according to IMAP rules.
Definition util.c:891
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_unmunge_mbox_name()

void imap_unmunge_mbox_name ( bool unicode,
char * s )

Remove quoting from a mailbox name.

Parameters
unicodetrue if Unicode is allowed
sMailbox name

The string will be altered in-place.

Definition at line 988 of file util.c.

989{
991
992 char *buf = mutt_str_dup(s);
993 if (buf)
994 {
995 imap_utf_decode(unicode, &buf);
996 strncpy(s, buf, strlen(s));
997 }
998
999 FREE(&buf);
1000}
void imap_utf_decode(bool unicode, char **s)
Decode email from UTF-8 to local charset.
Definition utf7.c:430
void imap_unquote_string(char *s)
Equally stupid unquoting routine.
Definition util.c:934
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_seqset_iterator_new()

struct SeqsetIterator * mutt_seqset_iterator_new ( const char * seqset)

Create a new Sequence Set Iterator.

Parameters
seqsetSource Sequence Set
Return values
ptrNewly allocated Sequence Set Iterator

Definition at line 1138 of file util.c.

1139{
1140 if (!seqset || (*seqset == '\0'))
1141 return NULL;
1142
1143 struct SeqsetIterator *iter = MUTT_MEM_CALLOC(1, struct SeqsetIterator);
1144 iter->full_seqset = mutt_str_dup(seqset);
1145 iter->eostr = strchr(iter->full_seqset, '\0');
1146 iter->substr_cur = iter->substr_end = iter->full_seqset;
1147
1148 return iter;
1149}
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
UID Sequence Set Iterator.
Definition private.h:185
char * eostr
End of string.
Definition private.h:187
char * substr_end
End of substring.
Definition private.h:193
char * substr_cur
Current position in substring.
Definition private.h:192
char * full_seqset
Full sequence set string.
Definition private.h:186
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_seqset_iterator_next()

int mutt_seqset_iterator_next ( struct SeqsetIterator * iter,
unsigned int * next )

Get the next UID from a Sequence Set.

Parameters
[in]iterSequence Set Iterator
[out]nextNext UID in set
Return values
0Next sequence is generated
1Iterator is finished
-1error

Definition at line 1159 of file util.c.

1160{
1161 if (!iter || !next)
1162 return -1;
1163
1164 if (iter->in_range)
1165 {
1166 if ((iter->down && (iter->range_cur == (iter->range_end - 1))) ||
1167 (!iter->down && (iter->range_cur == (iter->range_end + 1))))
1168 {
1169 iter->in_range = 0;
1170 }
1171 }
1172
1173 if (!iter->in_range)
1174 {
1175 iter->substr_cur = iter->substr_end;
1176 if (iter->substr_cur == iter->eostr)
1177 return 1;
1178
1179 iter->substr_end = strchr(iter->substr_cur, ',');
1180 if (!iter->substr_end)
1181 iter->substr_end = iter->eostr;
1182 else
1183 *(iter->substr_end++) = '\0';
1184
1185 char *range_sep = strchr(iter->substr_cur, ':');
1186 if (range_sep)
1187 *range_sep++ = '\0';
1188
1189 if (!mutt_str_atoui_full(iter->substr_cur, &iter->range_cur))
1190 return -1;
1191 if (range_sep)
1192 {
1193 if (!mutt_str_atoui_full(range_sep, &iter->range_end))
1194 return -1;
1195 }
1196 else
1197 {
1198 iter->range_end = iter->range_cur;
1199 }
1200
1201 iter->down = (iter->range_end < iter->range_cur);
1202 iter->in_range = 1;
1203 }
1204
1205 *next = iter->range_cur;
1206 if (iter->down)
1207 iter->range_cur--;
1208 else
1209 iter->range_cur++;
1210
1211 return 0;
1212}
unsigned int range_end
End of range.
Definition private.h:191
int down
Counting down.
Definition private.h:189
int in_range
Currently in a range.
Definition private.h:188
unsigned int range_cur
Current range value.
Definition private.h:190
+ Here is the caller graph for this function:

◆ mutt_seqset_iterator_free()

void mutt_seqset_iterator_free ( struct SeqsetIterator ** ptr)

Free a Sequence Set Iterator.

Parameters
[out]ptrIterator to free

Definition at line 1218 of file util.c.

1219{
1220 if (!ptr || !*ptr)
1221 return;
1222
1223 struct SeqsetIterator *iter = *ptr;
1224 FREE(&iter->full_seqset);
1225 FREE(ptr);
1226}
+ Here is the caller graph for this function:

◆ imap_account_match()

bool imap_account_match ( const struct ConnAccount * a1,
const struct ConnAccount * a2 )

Compare two Accounts.

Parameters
a1First ConnAccount
a2Second ConnAccount
Return values
trueAccounts match

Definition at line 1106 of file util.c.

1107{
1108 if (!a1 || !a2)
1109 return false;
1110 if (a1->type != a2->type)
1111 return false;
1112 if (!mutt_istr_equal(a1->host, a2->host))
1113 return false;
1114 if ((a1->port != 0) && (a2->port != 0) && (a1->port != a2->port))
1115 return false;
1116 if (a1->flags & a2->flags & MUTT_ACCT_USER)
1117 return mutt_str_equal(a1->user, a2->user);
1118
1119 const char *user = NONULL(NeoMutt->username);
1120
1121 const char *const c_imap_user = cs_subset_string(NeoMutt->sub, "imap_user");
1122 if ((a1->type == MUTT_ACCT_TYPE_IMAP) && c_imap_user)
1123 user = c_imap_user;
1124
1125 if (a1->flags & MUTT_ACCT_USER)
1126 return mutt_str_equal(a1->user, user);
1127 if (a2->flags & MUTT_ACCT_USER)
1128 return mutt_str_equal(a2->user, user);
1129
1130 return true;
1131}
@ MUTT_ACCT_USER
User field has been set.
Definition connaccount.h:48
@ MUTT_ACCT_TYPE_IMAP
Imap Account.
char user[128]
Username.
Definition connaccount.h:62
unsigned char type
Connection type, e.g. MUTT_ACCT_TYPE_IMAP.
Definition connaccount.h:65
MuttAccountFlags flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition connaccount.h:66
unsigned short port
Port to connect to.
Definition connaccount.h:64
char * username
User's login name.
Definition neomutt.h:56
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_get_parent()

void imap_get_parent ( const char * mbox,
char delim,
char * buf,
size_t buflen )

Get an IMAP folder's parent.

Parameters
mboxMailbox whose parent is to be determined
delimPath delimiter
bufBuffer for the result
buflenLength of the buffer

Definition at line 127 of file util.c.

128{
129 /* Make a copy of the mailbox name, but only if the pointers are different */
130 if (mbox != buf)
131 mutt_str_copy(buf, mbox, buflen);
132
133 int n = mutt_str_len(buf);
134
135 /* Let's go backwards until the next delimiter
136 *
137 * If buf[n] is a '/', the first n-- will allow us
138 * to ignore it. If it isn't, then buf looks like
139 * "/aaaaa/bbbb". There is at least one "b", so we can't skip
140 * the "/" after the 'a's.
141 *
142 * If buf == '/', then n-- => n == 0, so the loop ends
143 * immediately */
144 for (n--; (n >= 0) && (buf[n] != delim); n--)
145 ; // do nothing
146
147 /* We stopped before the beginning. There is a trailing slash. */
148 if (n > 0)
149 {
150 /* Strip the trailing delimiter. */
151 buf[n] = '\0';
152 }
153 else
154 {
155 buf[0] = (n == 0) ? delim : '\0';
156 }
157}
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:586
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_account_match()

bool mutt_account_match ( const struct ConnAccount * a1,
const struct ConnAccount * a2 )

◆ imap_utf_encode()

void imap_utf_encode ( bool unicode,
char ** s )

Encode email from local charset to UTF-8.

Parameters
[in]unicodetrue if Unicode is allowed
[out]sEmail to convert

Definition at line 397 of file utf7.c.

398{
399 if (!s || !*s)
400 return;
401
402 const char *c_charset = cc_charset();
403 if (!c_charset)
404 return;
405
406 if (unicode && mutt_ch_is_utf8(c_charset))
407 {
408 return;
409 }
410
411 if (mutt_ch_convert_string(s, c_charset, "utf-8", MUTT_ICONV_NONE) != 0)
412 {
413 FREE(s);
414 return;
415 }
416
417 if (!unicode)
418 {
419 char *utf7 = utf8_to_utf7(*s, strlen(*s), NULL, 0);
420 FREE(s);
421 *s = utf7;
422 }
423}
const char * cc_charset(void)
Get the cached value of $charset.
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition charset.c:817
#define MUTT_ICONV_NONE
No flags are set.
Definition charset.h:66
#define mutt_ch_is_utf8(str)
Definition charset.h:107
static char * utf8_to_utf7(const char *u8, size_t u8len, char **u7, size_t *u7len)
Convert data from UTF-8 to RFC2060's UTF-7.
Definition utf7.c:252
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_utf_decode()

void imap_utf_decode ( bool unicode,
char ** s )

Decode email from UTF-8 to local charset.

Parameters
[in]unicodetrue if Unicode is allowed
[out]sEmail to convert

Definition at line 430 of file utf7.c.

431{
432 if (!s || !*s)
433 return;
434
435 const char *c_charset = cc_charset();
436 if (!c_charset)
437 return;
438
439 if (unicode && mutt_ch_is_utf8(c_charset))
440 {
441 return;
442 }
443
444 if (!unicode)
445 {
446 char *utf8 = utf7_to_utf8(*s, strlen(*s), 0, 0);
447 FREE(s);
448 *s = utf8;
449 }
450
451 if (mutt_ch_convert_string(s, "utf-8", c_charset, MUTT_ICONV_NONE) != 0)
452 {
453 FREE(s);
454 }
455}
static char * utf7_to_utf8(const char *u7, size_t u7len, char **u8, size_t *u8len)
Convert data from RFC2060's UTF-7 to UTF-8.
Definition utf7.c:106
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_allow_reopen()

void imap_allow_reopen ( struct Mailbox * m)

Allow re-opening a folder upon expunge.

Parameters
mMailbox

Definition at line 1078 of file util.c.

1079{
1081 struct ImapMboxData *mdata = imap_mdata_get(m);
1082 if (!adata || !adata->mailbox || (adata->mailbox != m) || !mdata)
1083 return;
1084 mdata->reopen |= IMAP_REOPEN_ALLOW;
1085}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_disallow_reopen()

void imap_disallow_reopen ( struct Mailbox * m)

Disallow re-opening a folder upon expunge.

Parameters
mMailbox

Definition at line 1091 of file util.c.

1092{
1094 struct ImapMboxData *mdata = imap_mdata_get(m);
1095 if (!adata || !adata->mailbox || (adata->mailbox != m) || !mdata)
1096 return;
1097 mdata->reopen &= ~IMAP_REOPEN_ALLOW;
1098}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cmd_parse_search()

void cmd_parse_search ( struct ImapAccountData * adata,
const char * s )

Store SEARCH response for later use.

Parameters
adataImap Account data
sCommand string with search results

Definition at line 260 of file search.c.

261{
262 unsigned int uid;
263 struct Email *e = NULL;
264
265 if (!adata->mailbox)
266 return;
267
268 struct ImapMboxData *mdata = adata->mailbox->mdata;
269 if (!mdata)
270 return;
271
272 mutt_debug(LL_DEBUG2, "Handling SEARCH\n");
273
274 while ((s = imap_next_word((char *) s)) && (*s != '\0'))
275 {
276 if (!mutt_str_atoui(s, &uid))
277 continue;
278 e = mutt_hash_int_find(mdata->uid_hash, uid);
279 if (e)
280 e->matched = true;
281 }
282}
void * mutt_hash_int_find(const struct HashTable *table, unsigned int intkey)
Find the HashElem data in a Hash Table element using a key.
Definition hash.c:394
bool matched
Search matches this Email.
Definition email.h:102
+ Here is the call graph for this function:
+ Here is the caller graph for this function: