LCOV - code coverage report
Current view: top level - libemail/src/infrastructure - imap_client.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 5 5
Test Date: 2026-04-15 21:12:52 Functions: 100.0 % 1 1

            Line data    Source code
       1              : #ifndef IMAP_CLIENT_H
       2              : #define IMAP_CLIENT_H
       3              : 
       4              : #include <stddef.h>
       5              : 
       6              : /**
       7              :  * @file imap_client.h
       8              :  * @brief Minimal IMAP4rev1 client over TLS (OpenSSL) or plain TCP.
       9              :  *
      10              :  * Supports the operations needed by email-cli:
      11              :  *   - LIST "" "*"           — enumerate folders
      12              :  *   - SELECT <folder>       — open a folder
      13              :  *   - UID SEARCH <criteria> — find messages
      14              :  *   - UID FETCH <uid> BODY.PEEK[]        — fetch full message (no \Seen flag)
      15              :  *   - UID FETCH <uid> BODY.PEEK[HEADER]  — fetch headers only (no \Seen flag)
      16              :  *
      17              :  * Connection lifecycle:
      18              :  *   1. imap_connect()  — TCP connect, TLS handshake, read server greeting, LOGIN
      19              :  *   2. imap_select()   — SELECT a folder (required before SEARCH/FETCH)
      20              :  *   3. imap commands…
      21              :  *   4. imap_disconnect() — LOGOUT + close
      22              :  *
      23              :  * The URL format matches libcurl's IMAP convention:
      24              :  *   imaps://hostname           → TLS on port 993
      25              :  *   imaps://hostname:port      → TLS on custom port
      26              :  *   imap://hostname            → plain TCP on port 143
      27              :  *   imap://hostname:port       → plain TCP on custom port
      28              :  */
      29              : 
      30              : typedef struct ImapClient ImapClient;
      31              : 
      32              : /**
      33              :  * RAII cleanup helper — store pointer via RAII_IMAP so the client is
      34              :  * automatically disconnected when the variable goes out of scope.
      35              :  *
      36              :  * Usage:
      37              :  *   RAII_IMAP ImapClient *c = imap_connect(...);
      38              :  */
      39              : static inline void imap_disconnect_ptr(ImapClient **p);
      40              : #define RAII_IMAP __attribute__((cleanup(imap_disconnect_ptr)))
      41              : 
      42              : /**
      43              :  * @brief Connect to an IMAP server and authenticate.
      44              :  *
      45              :  * @param host_url   Server URL, e.g. "imaps://imap.example.com" or
      46              :  *                   "imaps://imap.example.com:993".
      47              :  * @param user       IMAP username.
      48              :  * @param pass       IMAP password.
      49              :  * @param verify_tls 1 = verify TLS certificate (production); 0 = accept
      50              :  *                   self-signed (test environments only).
      51              :  * @return New client handle, or NULL on failure.  Caller must call
      52              :  *         imap_disconnect() when done (or use RAII_IMAP).
      53              :  */
      54              : ImapClient *imap_connect(const char *host_url, const char *user,
      55              :                          const char *pass, int verify_tls);
      56              : 
      57              : /**
      58              :  * @brief Send LOGOUT and close the connection.
      59              :  * Safe to call with NULL.
      60              :  */
      61              : void imap_disconnect(ImapClient *c);
      62              : 
      63              : /**
      64              :  * @brief List all folders on the server (LIST "" "*").
      65              :  *
      66              :  * Folder names are decoded from IMAP Modified UTF-7 to UTF-8.
      67              :  *
      68              :  * @param c          Connected client handle.
      69              :  * @param folders_out  On success, set to a heap-allocated array of
      70              :  *                     heap-allocated folder name strings.  Caller frees each
      71              :  *                     element and then the array itself.
      72              :  * @param count_out  Number of folders returned.
      73              :  * @param sep_out    If non-NULL, set to the hierarchy separator character
      74              :  *                   (e.g. '.' or '/'); '.' if no separator found.
      75              :  * @return 0 on success, -1 on error.
      76              :  */
      77              : int imap_list(ImapClient *c, char ***folders_out, int *count_out, char *sep_out);
      78              : 
      79              : /**
      80              :  * @brief SELECT a folder.
      81              :  *
      82              :  * Must be called before imap_uid_search(), imap_uid_fetch_headers(), or
      83              :  * imap_uid_fetch_body().  Calling again with a different folder re-selects.
      84              :  *
      85              :  * @param c       Connected client handle.
      86              :  * @param folder  Folder name in UTF-8 (will be encoded to IMAP Modified UTF-7
      87              :  *                internally before sending to the server).
      88              :  * @return 0 on success, -1 on error.
      89              :  */
      90              : int imap_select(ImapClient *c, const char *folder);
      91              : 
      92              : /**
      93              :  * @brief UID SEARCH with caller-supplied criteria string.
      94              :  *
      95              :  * Typical criteria: "ALL", "UNSEEN".
      96              :  * Requires a folder to be selected first.
      97              :  *
      98              :  * @param c          Connected client handle.
      99              :  * @param criteria   IMAP search criteria string (e.g. "ALL", "UNSEEN").
     100              :  * @param uids_out   On success, set to a heap-allocated array of UIDs.
     101              :  *                   Caller must free().  Set to NULL if count is 0.
     102              :  * @param count_out  Number of UIDs returned (0 = empty result, not an error).
     103              :  * @return 0 on success (including empty result), -1 on error.
     104              :  */
     105              : int imap_uid_search(ImapClient *c, const char *criteria,
     106              :                     int **uids_out, int *count_out);
     107              : 
     108              : /**
     109              :  * @brief Fetch just the RFC 2822 headers for a message (BODY.PEEK[HEADER]).
     110              :  *
     111              :  * Does NOT set the \Seen flag.
     112              :  * Requires a folder to be selected first.
     113              :  *
     114              :  * @param c    Connected client handle.
     115              :  * @param uid  IMAP UID of the message.
     116              :  * @return Heap-allocated NUL-terminated string containing the raw headers,
     117              :  *         or NULL on error.  Caller must free().
     118              :  */
     119              : char *imap_uid_fetch_headers(ImapClient *c, int uid);
     120              : 
     121              : /**
     122              :  * @brief Fetch the complete RFC 2822 message (BODY.PEEK[]).
     123              :  *
     124              :  * Does NOT set the \Seen flag.
     125              :  * Requires a folder to be selected first.
     126              :  *
     127              :  * @param c    Connected client handle.
     128              :  * @param uid  IMAP UID of the message.
     129              :  * @return Heap-allocated NUL-terminated string containing the full raw message,
     130              :  *         or NULL on error.  Caller must free().
     131              :  */
     132              : char *imap_uid_fetch_body(ImapClient *c, int uid);
     133              : 
     134              : /**
     135              :  * @brief Fetch the IMAP FLAGS for a single message (UID FETCH uid (UID FLAGS)).
     136              :  *
     137              :  * Returns a bitmask of MSG_FLAG_* from local_store.h, or -1 on error.
     138              :  * Does NOT affect \Seen.
     139              :  */
     140              : int imap_uid_fetch_flags(ImapClient *c, int uid);
     141              : 
     142              : /**
     143              :  * @brief Set or clear a single IMAP flag on a message (UID STORE).
     144              :  *
     145              :  * @param flag_name  IMAP flag string, e.g. "\\Flagged" or "$Done".
     146              :  * @param add        1 = add flag (+FLAGS), 0 = remove flag (-FLAGS).
     147              :  * @return 0 on success, -1 on error.
     148              :  */
     149              : int imap_uid_set_flag(ImapClient *c, int uid, const char *flag_name, int add);
     150              : 
     151              : /**
     152              :  * @brief Append a message to an IMAP folder (IMAP APPEND command).
     153              :  *
     154              :  * Saves @p msg (a complete RFC 2822 message) to @p folder on the server,
     155              :  * flagged as \\Seen.  Used to store a copy of sent messages in the Sent folder.
     156              :  *
     157              :  * @param c        Connected and authenticated IMAP client.
     158              :  * @param folder   Destination folder name (e.g. "Sent").
     159              :  * @param msg      Raw RFC 2822 message bytes.
     160              :  * @param msg_len  Length of @p msg in bytes.
     161              :  * @return 0 on success, -1 on error.
     162              :  */
     163              : int imap_append(ImapClient *c, const char *folder,
     164              :                 const char *msg, size_t msg_len);
     165              : 
     166              : /**
     167              :  * @brief Progress callback type for large literal downloads.
     168              :  *
     169              :  * @param received  Bytes received so far.
     170              :  * @param total     Total bytes expected (literal size announced by server).
     171              :  * @param ctx       User-supplied context pointer passed to imap_set_progress().
     172              :  */
     173              : typedef void (*ImapProgressFn)(size_t received, size_t total, void *ctx);
     174              : 
     175              : /**
     176              :  * @brief Install (or clear) a download-progress callback on the client.
     177              :  *
     178              :  * The callback is invoked periodically while reading large IMAP literals
     179              :  * (bodies >= ~100 KB).  Pass fn=NULL to disable.
     180              :  * The callback is NOT cleared automatically after a fetch; call
     181              :  * imap_set_progress(c, NULL, NULL) when no longer needed.
     182              :  */
     183              : void imap_set_progress(ImapClient *c, ImapProgressFn fn, void *ctx);
     184              : 
     185              : /* ── Inline RAII cleanup ─────────────────────────────────────────────── */
     186              : 
     187           51 : static inline void imap_disconnect_ptr(ImapClient **p) {
     188           51 :     if (p && *p) {
     189           51 :         imap_disconnect(*p);
     190           51 :         *p = NULL;
     191              :     }
     192           51 : }
     193              : 
     194              : #endif /* IMAP_CLIENT_H */
        

Generated by: LCOV version 2.0-1