From 5246f3fadc5c8a033559909b22f9c4a638841f85 Mon Sep 17 00:00:00 2001 From: Bruno Date: Mon, 13 Oct 2025 15:24:47 +0200 Subject: [PATCH] 1st, 2st, 3st, and 4st -- added the UID to the FETCH message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On branch master Your branch is up to date with 'origin/master'. Changes to be committed: modified: imap-common.c modified lines 1153 and 1188 adding UID FETCH instead of just FETCH, hopefully now fdm will get all of gmail's special headers like X-GM-LABELS, X-GM-THRID, and X-GM-MSGID removed one UID FETCH because the return msg apparently the IMAP server does not reply UID FETCH rather just FETCH added the necessary logic to locate the " UID {UID}" at the end of the IMAP server's reply to the UID FETCH instruction, correctly assuming that everything that is in the message between X-GM-LABELS and UID are the labels, it even checks for the special case where there are no gmail labels. Note: Gmail is extra special with labels, because if you tell fdm to fetch all email from a single label, that label is not returned by gmail and fdm will never see it. This is because gmail treats labels as virtual folders. Not happy with the code, and I think it can be further improved, it's still quite fast, and I've yet to find another edge case with labels. So far so good. modified: configure.ac added version info, but somehow doesn't stick, I wanted to call this program fdm_i 2.2i_1 but ¯\_(ツ)_/¯, it ain't workin... --- .gitmessage | 6 ++++++ configure.ac | 4 ++-- imap-common.c | 40 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 .gitmessage diff --git a/.gitmessage b/.gitmessage new file mode 100644 index 0000000..ac6a0d7 --- /dev/null +++ b/.gitmessage @@ -0,0 +1,6 @@ +# TITLE +# No more than 50 chars ##### 50 chars is here: # + +# Leave a blank line between title and body +# BODY +# Wrap at 72 chars ################################ 72 chars is here: # diff --git a/configure.ac b/configure.ac index 4b1d6fe..6974638 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ # $Id$ -AC_INIT(fdm, 2.2) -RELEASE=2.2 +AC_INIT(fdm_i, 2.2i.0) +RELEASE=2.2i.0 AC_SUBST(RELEASE) AC_CONFIG_AUX_DIR(etc) diff --git a/imap-common.c b/imap-common.c index a086992..cf41caa 100644 --- a/imap-common.c +++ b/imap-common.c @@ -1150,7 +1150,7 @@ imap_state_gmext_start(struct account *a, struct fetch_ctx *fctx) struct mail *m = fctx->mail; struct fetch_imap_mail *aux = m->auxdata; - if (imap_putln(a, "%u FETCH %u (X-GM-MSGID X-GM-THRID X-GM-LABELS)", + if (imap_putln(a, "%u UID FETCH %u (X-GM-MSGID X-GM-THRID X-GM-LABELS)", ++data->tag, aux->uid) != 0) return (FETCH_ERROR); @@ -1169,6 +1169,12 @@ imap_state_gmext_body(struct account *a, struct fetch_ctx *fctx) u_int n; uint64_t thrid, msgid; size_t lblen; + // 0. new variables + struct fetch_imap_mail *aux = m->auxdata; /* required to know what is the current UID */ + char uid_search_buffer[32]; + char *uid_terminator; + char original_char; + unsigned int guid; for (;;) { if (imap_getln(a, fctx, IMAP_RAW, &line) != 0) @@ -1193,10 +1199,36 @@ imap_state_gmext_body(struct account *a, struct fetch_ctx *fctx) if ((lb = strchr(lb, '(')) == NULL) return (imap_invalid(a, line)); lb++; /* drop '(' */ + + // 1. Find the unique UID terminator: " UID n)" where n is aux->uid + if (snprintf(uid_search_buffer, sizeof(uid_search_buffer), " UID %u)", aux->uid) <= 0) + return (imap_invalid(a, line)); + + uid_terminator = strstr(line, uid_search_buffer); + if (uid_terminator == NULL) + return (imap_invalid(a, line)); + + // 2. Temporarily null-terminate the string before " UID n)" + original_char = *uid_terminator; + *uid_terminator = '\0'; + lblen = strlen(lb); - if (lblen < 2 || lb[lblen - 1] != ')' || lb[lblen - 2] != ')') - return (imap_invalid(a, line)); - lblen -= 2; /* drop '))' from the end */ + + // 3. Handle empty labels () and non-empty labels (check + strip trailing ')') + if (lblen == 1 && lb[0] == ')') { + lblen = 0; // No labels found (a gmail label is like a virtual IMAP folder), set length to zero + } + else { + // Non-empty labels: check for final ')' and remove it + if (lblen < 2 || lb[lblen - 1] != ')') { + *uid_terminator = original_char; // bring back original terminator + return (imap_invalid(a, line)); + } + lblen -= 1; // drop ')' from the end + } + + // 4. Restore the character temporarily overwritten + *uid_terminator = original_char; // maybe necessary for logging add_tag(&m->tags, "gmail_msgid", "%llu", msgid); add_tag(&m->tags, "gmail_thrid", "%llu", thrid);