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-05-07 15:53:08 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              : /**
     130              :  * @brief Move a message to a different IMAP folder (UID COPY + STORE \Deleted + EXPUNGE).
     131              :  *  For Gmail accounts this is a no-op (label-based; use mail_client_modify_label instead).
     132              :  */
     133              : int mail_client_move_to_folder(MailClient *c, const char *uid, const char *target_folder);
     134              : 
     135              : /**
     136              :  * @brief Append/send a message.
     137              :  *
     138              :  * IMAP: APPEND to the specified folder.
     139              :  * Gmail: messages.send() via REST API (folder parameter ignored).
     140              :  */
     141              : int mail_client_append(MailClient *c, const char *folder,
     142              :                        const char *msg, size_t msg_len);
     143              : 
     144              : /**
     145              :  * @brief List folders (IMAP) or labels (Gmail), returning both display names and IDs.
     146              :  * For IMAP, names and IDs are the same string.
     147              :  * @param names_out  Heap-alloc'd array of display names. Caller frees each + array.
     148              :  * @param ids_out    Heap-alloc'd array of IDs (parallel). Caller frees each + array.
     149              :  * @param count_out  Number of entries.
     150              :  * @return 0 on success, -1 on error.
     151              :  */
     152              : int mail_client_list_with_ids(MailClient *c, char ***names_out,
     153              :                               char ***ids_out, int *count_out);
     154              : 
     155              : /**
     156              :  * @brief Create a Gmail label. Fails if called on an IMAP account.
     157              :  * @param name   Display name for the new label.
     158              :  * @param id_out Optional: receives new label ID. Caller frees.
     159              :  * @return 0 on success, -1 on error.
     160              :  */
     161              : int mail_client_create_label(MailClient *c, const char *name, char **id_out);
     162              : 
     163              : /**
     164              :  * @brief Delete a Gmail label. Fails if called on an IMAP account.
     165              :  * @param label_id  Label ID (from list-labels).
     166              :  * @return 0 on success, -1 on error.
     167              :  */
     168              : int mail_client_delete_label(MailClient *c, const char *label_id);
     169              : 
     170              : /**
     171              :  * @brief Create an IMAP folder. Fails if called on a Gmail account.
     172              :  * @param name  Folder path / name.
     173              :  * @return 0 on success, -1 on error.
     174              :  */
     175              : int mail_client_create_folder(MailClient *c, const char *name);
     176              : 
     177              : /**
     178              :  * @brief Delete an IMAP folder. Fails if called on a Gmail account.
     179              :  * @param name  Folder path / name.
     180              :  * @return 0 on success, -1 on error.
     181              :  */
     182              : int mail_client_delete_folder(MailClient *c, const char *name);
     183              : 
     184              : /**
     185              :  * @brief Add or remove a label on a Gmail message (no-op for IMAP).
     186              :  *
     187              :  * @param label_id  Gmail label ID (e.g. "INBOX", "STARRED", "Work").
     188              :  * @param add       1 = add label, 0 = remove label.
     189              :  * @return 0 on success, -1 on error. Always returns 0 for IMAP (no-op).
     190              :  */
     191              : int mail_client_modify_label(MailClient *c, const char *uid,
     192              :                              const char *label_id, int add);
     193              : 
     194              : /**
     195              :  * @brief Install a progress callback for large downloads.
     196              :  */
     197              : void mail_client_set_progress(MailClient *c, ImapProgressFn fn, void *ctx);
     198              : 
     199              : /* ── Incremental sync (CONDSTORE / QRESYNC) ─────────────────────────────── */
     200              : 
     201              : /**
     202              :  * @brief Extended SELECT with CONDSTORE/QRESYNC support.
     203              :  *
     204              :  * Selects the folder. For IMAP with CONDSTORE/QRESYNC the server is asked
     205              :  * for incremental sync information; for Gmail this is a no-op SELECT.
     206              :  *
     207              :  * Pass known_uidval=0 / known_modseq=0 on first run or after a forced
     208              :  * reconcile; the server will respond with full state.
     209              :  *
     210              :  * @param known_uidval  Last saved UIDVALIDITY (0 = no saved state).
     211              :  * @param known_modseq  Last saved HIGHESTMODSEQ (0 = no saved state).
     212              :  * @param res_out       Filled on return. Caller must free res_out->vanished_uids.
     213              :  * @return 0 on success, -1 on error.
     214              :  */
     215              : int mail_client_select_ext(MailClient *c, const char *folder,
     216              :                             uint32_t known_uidval, uint64_t known_modseq,
     217              :                             ImapSelectResult *res_out);
     218              : 
     219              : /**
     220              :  * @brief Fetch flag updates for messages changed since @p modseq.
     221              :  *
     222              :  * IMAP: sends UID FETCH 1:* (UID FLAGS) (CHANGEDSINCE modseq).
     223              :  * Gmail: not supported — returns empty result (success).
     224              :  *
     225              :  * @param modseq     Messages with modseq > this value are returned.
     226              :  * @param out        Set to heap-alloc'd ImapFlagUpdate array. Caller frees.
     227              :  * @param count_out  Number of entries.
     228              :  * @return 0 on success, -1 on error.
     229              :  */
     230              : int mail_client_fetch_flags_changedsince(MailClient *c, uint64_t modseq,
     231              :                                           ImapFlagUpdate **out, int *count_out);
     232              : 
     233              : /**
     234              :  * @brief Synchronise the account (Gmail: full/incremental sync).
     235              :  *
     236              :  * For IMAP this is a no-op (sync is handled by email_service_sync).
     237              :  * For Gmail this delegates to gmail_sync().
     238              :  */
     239              : int mail_client_sync(MailClient *c);
     240              : 
     241              : /* ── Inline RAII cleanup ─────────────────────────────────────��────── */
     242              : 
     243          205 : static inline void mail_client_free_ptr(MailClient **p) {
     244          205 :     if (p && *p) {
     245          180 :         mail_client_free(*p);
     246          180 :         *p = NULL;
     247              :     }
     248          205 : }
     249              : 
     250              : #endif /* MAIL_CLIENT_H */
        

Generated by: LCOV version 2.0-1