LCOV - code coverage report
Current view: top level - libemail/src/infrastructure - mail_client.h (source / functions) Coverage Total Hit
Test: coverage-functional.info Lines: 100.0 % 5 5
Test Date: 2026-08-21 10:11:30 Functions: 100.0 % 1 1

            Line data    Source code
       1              : #ifndef MAIL_CLIENT_H
       2              : #define MAIL_CLIENT_H
       3              : 
       4              : #include "config.h"
       5              : #include "imap_client.h"
       6              : #include <stddef.h>
       7              : 
       8              : /**
       9              :  * @file mail_client.h
      10              :  * @brief Unified dispatch layer for IMAP and Gmail backends.
      11              :  *
      12              :  * Sits between email_service.c and the protocol-specific clients.
      13              :  * cfg->gmail_mode selects the backend at connect time.
      14              :  */
      15              : 
      16              : typedef struct MailClient MailClient;
      17              : 
      18              : /** Semantic search criteria (protocol-independent). */
      19              : typedef enum {
      20              :     MAIL_SEARCH_ALL,
      21              :     MAIL_SEARCH_UNREAD,    /**< IMAP: UNSEEN; Gmail: has UNREAD label */
      22              :     MAIL_SEARCH_FLAGGED,   /**< IMAP: FLAGGED; Gmail: has STARRED label */
      23              :     MAIL_SEARCH_DONE,      /**< IMAP: KEYWORD $Done; Gmail: not used yet */
      24              : } MailSearchCriteria;
      25              : 
      26              : /** RAII cleanup helper. */
      27              : static inline void mail_client_free_ptr(MailClient **p);
      28              : #define RAII_MAIL __attribute__((cleanup(mail_client_free_ptr)))
      29              : 
      30              : /**
      31              :  * @brief Connect to the mail backend specified by cfg.
      32              :  *
      33              :  * If cfg->gmail_mode: uses Gmail REST API (OAuth2).
      34              :  * Otherwise: uses IMAP over TLS.
      35              :  *
      36              :  * @param cfg  Account configuration (borrowed, not copied).
      37              :  * @return New client handle, or NULL on failure.
      38              :  */
      39              : MailClient *mail_client_connect(Config *cfg);
      40              : 
      41              : /** @brief Disconnect and free the client. Safe to call with NULL. */
      42              : void mail_client_free(MailClient *c);
      43              : 
      44              : /** @brief Returns 1 for Gmail (label-based), 0 for IMAP (folder-based). */
      45              : int mail_client_uses_labels(const MailClient *c);
      46              : 
      47              : /**
      48              :  * @brief List folders (IMAP) or labels (Gmail).
      49              :  *
      50              :  * @param c          Connected client.
      51              :  * @param names_out  Heap-allocated array of name strings. Caller frees each + array.
      52              :  * @param count_out  Number of entries.
      53              :  * @param sep_out    Hierarchy separator (IMAP only; '/' for Gmail). May be NULL.
      54              :  * @return 0 on success, -1 on error.
      55              :  */
      56              : int mail_client_list(MailClient *c, char ***names_out, int *count_out, char *sep_out);
      57              : 
      58              : /**
      59              :  * @brief Select a folder (IMAP) or set the active label filter (Gmail).
      60              :  *
      61              :  * Must be called before search/fetch operations.
      62              :  */
      63              : int mail_client_select(MailClient *c, const char *name);
      64              : 
      65              : /**
      66              :  * @brief Search for messages matching criteria within the selected folder/label.
      67              :  *
      68              :  * @param c          Connected client.
      69              :  * @param criteria   Semantic search criteria.
      70              :  * @param uids_out   Heap-allocated array of 16-char UID strings. Caller must free().
      71              :  * @param count_out  Number of UIDs.
      72              :  * @return 0 on success, -1 on error.
      73              :  */
      74              : int mail_client_search(MailClient *c, MailSearchCriteria criteria,
      75              :                        char (**uids_out)[17], int *count_out);
      76              : 
      77              : /**
      78              :  * @brief Fetch raw RFC 2822 headers for a message.
      79              :  * @return Heap-allocated headers string, or NULL. Caller must free().
      80              :  */
      81              : char *mail_client_fetch_headers(MailClient *c, const char *uid);
      82              : 
      83              : /**
      84              :  * @brief Fetch the complete raw RFC 2822 message.
      85              :  * @return Heap-allocated message string, or NULL. Caller must free().
      86              :  */
      87              : char *mail_client_fetch_body(MailClient *c, const char *uid);
      88              : 
      89              : /**
      90              :  * @brief Fetch IMAP flags / Gmail label-derived flags as bitmask.
      91              :  * @return MSG_FLAG_* bitmask, or -1 on error.
      92              :  */
      93              : int mail_client_fetch_flags(MailClient *c, const char *uid);
      94              : 
      95              : /**
      96              :  * @brief Set or clear a flag on a message.
      97              :  *
      98              :  * IMAP: sends UID STORE.
      99              :  * Gmail: translates flag to label modify (e.g. \\Seen → remove UNREAD).
     100              :  *
     101              :  * @param flag  IMAP-style flag name (e.g. "\\Seen", "\\Flagged", "$Done").
     102              :  * @param add   1 = add, 0 = remove.
     103              :  */
     104              : int mail_client_set_flag(MailClient *c, const char *uid,
     105              :                          const char *flag, int add);
     106              : 
     107              : /**
     108              :  * @brief Mark a message as junk/spam.
     109              :  * IMAP: sets $Junk, clears $NotJunk.
     110              :  * Gmail: adds SPAM label, removes INBOX.
     111              :  */
     112              : int mail_client_mark_junk(MailClient *c, const char *uid);
     113              : 
     114              : /**
     115              :  * @brief Mark a message as not-junk (ham).
     116              :  * IMAP: sets $NotJunk, clears $Junk.
     117              :  * Gmail: removes SPAM label, adds INBOX.
     118              :  */
     119              : int mail_client_mark_notjunk(MailClient *c, const char *uid);
     120              : 
     121              : /**
     122              :  * @brief Move a message to Trash.
     123              :  *
     124              :  * IMAP: sets \\Deleted flag (caller may need EXPUNGE).
     125              :  * Gmail: compound trash operation (removes all labels, adds TRASH).
     126              :  */
     127              : int mail_client_trash(MailClient *c, const char *uid);
     128              : 
     129              : /** @brief Permanently delete a message (IMAP: \\Deleted + EXPUNGE; Gmail: messages.delete). */
     130              : int mail_client_delete(MailClient *c, const char *uid);
     131              : 
     132              : /**
     133              :  * @brief Move a message to a different IMAP folder (UID COPY + STORE \Deleted + EXPUNGE).
     134              :  *  For Gmail accounts this is a no-op (label-based; use mail_client_modify_label instead).
     135              :  */
     136              : int mail_client_move_to_folder(MailClient *c, const char *uid, const char *target_folder);
     137              : 
     138              : /**
     139              :  * @brief Append/send a message.
     140              :  *
     141              :  * IMAP: APPEND to the specified folder.
     142              :  * Gmail: messages.send() via REST API (folder parameter ignored).
     143              :  */
     144              : int mail_client_append(MailClient *c, const char *folder,
     145              :                        const char *msg, size_t msg_len);
     146              : 
     147              : /**
     148              :  * @brief List folders (IMAP) or labels (Gmail), returning both display names and IDs.
     149              :  * For IMAP, names and IDs are the same string.
     150              :  * @param names_out  Heap-alloc'd array of display names. Caller frees each + array.
     151              :  * @param ids_out    Heap-alloc'd array of IDs (parallel). Caller frees each + array.
     152              :  * @param count_out  Number of entries.
     153              :  * @return 0 on success, -1 on error.
     154              :  */
     155              : int mail_client_list_with_ids(MailClient *c, char ***names_out,
     156              :                               char ***ids_out, int *count_out);
     157              : 
     158              : /**
     159              :  * @brief Create a Gmail label. Fails if called on an IMAP account.
     160              :  * @param name   Display name for the new label.
     161              :  * @param id_out Optional: receives new label ID. Caller frees.
     162              :  * @return 0 on success, -1 on error.
     163              :  */
     164              : int mail_client_create_label(MailClient *c, const char *name, char **id_out);
     165              : 
     166              : /**
     167              :  * @brief Delete a Gmail label. Fails if called on an IMAP account.
     168              :  * @param label_id  Label ID (from list-labels).
     169              :  * @return 0 on success, -1 on error.
     170              :  */
     171              : int mail_client_delete_label(MailClient *c, const char *label_id);
     172              : 
     173              : /**
     174              :  * @brief Create an IMAP folder. Fails if called on a Gmail account.
     175              :  * @param name  Folder path / name.
     176              :  * @return 0 on success, -1 on error.
     177              :  */
     178              : int mail_client_create_folder(MailClient *c, const char *name);
     179              : 
     180              : /**
     181              :  * @brief Delete an IMAP folder. Fails if called on a Gmail account.
     182              :  * @param name  Folder path / name.
     183              :  * @return 0 on success, -1 on error.
     184              :  */
     185              : int mail_client_delete_folder(MailClient *c, const char *name);
     186              : 
     187              : /**
     188              :  * @brief Add or remove a label on a Gmail message (no-op for IMAP).
     189              :  *
     190              :  * @param label_id  Gmail label ID (e.g. "INBOX", "STARRED", "Work").
     191              :  * @param add       1 = add label, 0 = remove label.
     192              :  * @return 0 on success, -1 on error. Always returns 0 for IMAP (no-op).
     193              :  */
     194              : int mail_client_modify_label(MailClient *c, const char *uid,
     195              :                              const char *label_id, int add);
     196              : 
     197              : /**
     198              :  * @brief Install a progress callback for large downloads.
     199              :  */
     200              : void mail_client_set_progress(MailClient *c, ImapProgressFn fn, void *ctx);
     201              : 
     202              : /* ── Incremental sync (CONDSTORE / QRESYNC) ─────────────────────────────── */
     203              : 
     204              : /**
     205              :  * @brief Extended SELECT with CONDSTORE/QRESYNC support.
     206              :  *
     207              :  * Selects the folder. For IMAP with CONDSTORE/QRESYNC the server is asked
     208              :  * for incremental sync information; for Gmail this is a no-op SELECT.
     209              :  *
     210              :  * Pass known_uidval=0 / known_modseq=0 on first run or after a forced
     211              :  * reconcile; the server will respond with full state.
     212              :  *
     213              :  * @param known_uidval  Last saved UIDVALIDITY (0 = no saved state).
     214              :  * @param known_modseq  Last saved HIGHESTMODSEQ (0 = no saved state).
     215              :  * @param res_out       Filled on return. Caller must free res_out->vanished_uids.
     216              :  * @return 0 on success, -1 on error.
     217              :  */
     218              : int mail_client_select_ext(MailClient *c, const char *folder,
     219              :                             uint32_t known_uidval, uint64_t known_modseq,
     220              :                             ImapSelectResult *res_out);
     221              : 
     222              : /**
     223              :  * @brief Fetch flag updates for messages changed since @p modseq.
     224              :  *
     225              :  * IMAP: sends UID FETCH 1:* (UID FLAGS) (CHANGEDSINCE modseq).
     226              :  * Gmail: not supported — returns empty result (success).
     227              :  *
     228              :  * @param modseq     Messages with modseq > this value are returned.
     229              :  * @param out        Set to heap-alloc'd ImapFlagUpdate array. Caller frees.
     230              :  * @param count_out  Number of entries.
     231              :  * @return 0 on success, -1 on error.
     232              :  */
     233              : int mail_client_fetch_flags_changedsince(MailClient *c, uint64_t modseq,
     234              :                                           ImapFlagUpdate **out, int *count_out);
     235              : 
     236              : /**
     237              :  * @brief Synchronise the account (Gmail: full/incremental sync).
     238              :  *
     239              :  * For IMAP this is a no-op (sync is handled by email_service_sync).
     240              :  * For Gmail this delegates to gmail_sync().
     241              :  */
     242              : int mail_client_sync(MailClient *c);
     243              : 
     244              : /* ── Inline RAII cleanup ─────────────────────────────────────��────── */
     245              : 
     246          381 : static inline void mail_client_free_ptr(MailClient **p) {
     247          381 :     if (p && *p) {
     248          308 :         mail_client_free(*p);
     249          308 :         *p = NULL;
     250              :     }
     251          381 : }
     252              : 
     253              : #endif /* MAIL_CLIENT_H */
        

Generated by: LCOV version 2.0-1