summaryrefslogtreecommitdiff
path: root/imap
diff options
context:
space:
mode:
authorEduardo Chappa <chappa@washington.edu>2018-05-21 20:52:20 -0600
committerEduardo Chappa <chappa@washington.edu>2018-05-21 20:52:20 -0600
commit854ecc5e92a29f14983fc3c9c2edeb4980949568 (patch)
treef0c000b178c16689374441fc4da2a0371b9773c1 /imap
parent20e0e95b93f7f1eada65ac6b8e7729534537618c (diff)
downloadalpine-854ecc5e92a29f14983fc3c9c2edeb4980949568.tar.xz
* Add the "g" option to the select command that works in IMAP
servers that implement the X-GM-EXT-1 capability (such as the one offered by Gmail.) This allows users to do selection in Alpine as if they were doing a search in the web interface for Gmail.
Diffstat (limited to 'imap')
-rw-r--r--imap/src/c-client/imap4r1.c244
-rw-r--r--imap/src/c-client/imap4r1.h6
-rw-r--r--imap/src/c-client/mail.c1
-rw-r--r--imap/src/c-client/mail.h1
4 files changed, 249 insertions, 3 deletions
diff --git a/imap/src/c-client/imap4r1.c b/imap/src/c-client/imap4r1.c
index 13aaadab..343e29bf 100644
--- a/imap/src/c-client/imap4r1.c
+++ b/imap/src/c-client/imap4r1.c
@@ -1,7 +1,7 @@
/*
- * Copyright 2016 Eduardo Chappa
+ * Copyright 2016-2018 Eduardo Chappa
*
- * Last Edited: February 1, 2015 Eduardo Chappa <chappa@gmx.com>
+ * Last Edited: May 5, 2018 Eduardo Chappa <alpine.chappa@gmx.com>
*
*/
/* ========================================================================
@@ -191,6 +191,7 @@ unsigned long imap_uid (MAILSTREAM *stream,unsigned long msgno);
unsigned long imap_msgno (MAILSTREAM *stream,unsigned long uid);
void imap_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
long imap_search (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags);
+long imap_search_x_gm_ext1 (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags);
unsigned long *imap_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
SORTPGM *pgm,long flags);
THREADNODE *imap_thread (MAILSTREAM *stream,char *type,char *charset,
@@ -2023,6 +2024,10 @@ long imap_search (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags)
char *s;
IMAPPARSEDREPLY *reply;
MESSAGECACHE *elt;
+
+ if(LOCAL->cap.x_gm_ext1 && pgm && pgm->x_gm_ext1)
+ return imap_search_x_gm_ext1(stream, charset, pgm, flags);
+
if ((flags & SE_NOSERVER) || /* if want to do local search */
LOCAL->loser || /* or loser */
(!LEVELIMAP4 (stream) && /* or old server but new functions... */
@@ -3339,7 +3344,239 @@ IMAPPARSEDREPLY *imap_send_literal (MAILSTREAM *stream,char *tag,char **s,
}
return NIL; /* success */
}
-
+
+#define ADD_STRING(X, Y) { \
+ if(remain > 0){ \
+ sprintf (u, (X), (Y)); \
+ len = strlen(u); \
+ if(len < remain){ \
+ remain -= len; \
+ strncpy(t, u, strlen(u)); \
+ t[strlen(u)] = '\0'; \
+ t += strlen (t); \
+ } \
+ } \
+ }
+
+
+long imap_search_x_gm_ext1 (MAILSTREAM *stream, char *charset, SEARCHPGM *pgm, long flags)
+{
+ char *cmd = (flags & SE_UID) ? "UID SEARCH X-GM-RAW" : "SEARCH X-GM-RAW";
+ char *p, *t, s[MAILTMPLEN+1], u[MAILTMPLEN], v[MAILTMPLEN];
+ IMAPARG *args[4],apgm,aatt,achs;;
+ IMAPPARSEDREPLY *reply;
+ unsigned long i,j,k;
+ MESSAGECACHE *elt;
+ size_t remain = sizeof(s) - 1, len;
+ NETMBX mb;
+
+ u[0] = s[0] = '\0';
+ t = s;
+ args[1] = args[2] = args[3] = NIL;
+
+ if(pgm->x_gm_ext1)
+ ADD_STRING(" %s", pgm->x_gm_ext1->text.data);
+
+#if 0 /* maybe later */
+ if (pgm->larger)
+ ADD_STRING(" larger:%lu", pgm->larger);
+
+ if (pgm->smaller)
+ ADD_STRING(" smaller:%lu", pgm->smaller);
+
+ if (pgm->deleted)
+ ADD_STRING(" %s", "in:trash");
+
+ if (pgm->undeleted)
+ ADD_STRING(" %s", "-in:trash");
+
+ if (pgm->draft)
+ ADD_STRING(" %s", "in:drafts");
+
+ if (pgm->undraft)
+ ADD_STRING(" %s", "-in:drafts");
+
+ if (pgm->flagged)
+ ADD_STRING(" %s", "is:starred");
+
+ if (pgm->unflagged)
+ ADD_STRING(" %s", "-is:starred");
+
+ if (pgm->seen)
+ ADD_STRING(" %s", "-is:unread");
+
+ if (pgm->unseen)
+ ADD_STRING(" %s", "is:unread");
+
+ if (pgm->keyword){
+ STRINGLIST *sl;
+ for(sl = pgm->keyword; remain > 0 && sl; sl = sl->next)
+ ADD_STRING(" label:%s", sl->text.data);
+ }
+
+ if (pgm->unkeyword){
+ STRINGLIST *sl;
+ for(sl = pgm->unkeyword; remain > 0 && sl; sl = sl->next)
+ ADD_STRING(" -label:%s", sl->text.data);
+ }
+
+ if (pgm->sentbefore){
+ unsigned short date = pgm->sentbefore;
+ sprintf(v, "%d/%d/%d", BASEYEAR + (date >> 9),
+ (date >> 5) & 0xf, date & 0x1f);
+ ADD_STRING(" before:%s", v);
+ }
+
+ if (pgm->sentsince){
+ unsigned short date = pgm->sentsince;
+ sprintf(v, "%d/%d/%d", BASEYEAR + (date >> 9),
+ (date >> 5) & 0xf, date & 0x1f);
+ ADD_STRING(" older:%s", v);
+ }
+
+ if (pgm->before){
+ unsigned short date = pgm->before;
+ sprintf(v, "%d/%d/%d", BASEYEAR + (date >> 9),
+ (date >> 5) & 0xf, date & 0x1f);
+ ADD_STRING(" before:%s", v);
+ }
+
+ if (pgm->since){
+ unsigned short date = pgm->since;
+ sprintf(v, "%d/%d/%d", BASEYEAR + (date >> 9),
+ (date >> 5) & 0xf, date & 0x1f);
+ ADD_STRING(" before:%s", v);
+ }
+
+ if (pgm->older){
+ sprintf(v, "%dd", pgm->older/86400);
+ ADD_STRING(" older_than:%s", v);
+ }
+
+ if (pgm->younger){
+ sprintf(v, "%dd", pgm->younger/86400);
+ ADD_STRING(" newer_than:%s", v);
+ }
+
+ if(pgm->bcc){
+ STRINGLIST *sl;
+ ADD_STRING("%s", pgm->bcc->next ? " {" : " ");
+ for(sl = pgm->bcc; remain > 0 && sl; sl = sl->next){
+ ADD_STRING("bcc:%s", sl->text.data);
+ ADD_STRING("%s", sl->next ? " " : "}");
+ }
+ }
+
+ if(pgm->cc){
+ STRINGLIST *sl;
+ ADD_STRING("%s", pgm->cc->next ? " {" : " ");
+ for(sl = pgm->cc; remain > 0 && sl; sl = sl->next){
+ ADD_STRING("cc:%s", sl->text.data);
+ ADD_STRING("%s", sl->next ? " " : "}");
+ }
+ }
+
+ if(pgm->from){
+ STRINGLIST *sl;
+ ADD_STRING("%s", pgm->from->next ? " {" : " ");
+ for(sl = pgm->from; remain > 0 && sl; sl = sl->next){
+ ADD_STRING("from:%s", sl->text.data);
+ ADD_STRING("%s", sl->next ? " " : (pgm->from->next ? "}" : ""));
+ }
+ }
+
+ if(pgm->to){
+ STRINGLIST *sl;
+ ADD_STRING("%s", pgm->to->next ? " {" : " ");
+ for(sl = pgm->to; remain > 0 && sl; sl = sl->next){
+ ADD_STRING("to:%s", sl->text.data);
+ ADD_STRING("%s", sl->next ? " " : (pgm->to->next ? "}" : ""));
+ }
+ }
+
+ if(pgm->subject){
+ STRINGLIST *sl;
+ ADD_STRING("%s", pgm->subject->next ? " {" : " ");
+ for(sl = pgm->subject; remain > 0 && sl; sl = sl->next){
+ ADD_STRING("subject:(%s)", sl->text.data);
+ ADD_STRING("%s", sl->next ? " " : (pgm->subject->next ? "}" : ""));
+ }
+ }
+
+ if(pgm->body){
+ STRINGLIST *sl;
+ ADD_STRING("%s", pgm->body->next ? " {" : " ");
+ for(sl = pgm->body; remain > 0 && sl; sl = sl->next){
+ ADD_STRING(" %s", sl->text.data);
+ ADD_STRING("%s", sl->next ? " " : (pgm->body->next ? "}" : ""));
+ }
+ }
+
+ if (mail_valid_net_parse (stream->mailbox,&mb)){
+ p = strchr(mb.mailbox, '/');
+ ADD_STRING(" in:%s", p ? p+1 : "inbox");
+ }
+
+#endif /* maybe later */
+
+ s[0] = '\"';
+ strcat(t, "\"");
+
+ apgm.type = ATOM; apgm.text = (void *) s;
+ args[0] = &apgm;
+ args[1] = NIL;
+ LOCAL->uidsearch = (flags & SE_UID) ? T : NIL;
+ reply = imap_send (stream,cmd,args);
+ LOCAL->uidsearch = NIL;
+ /* do locally if server won't grok */
+ if (!strcmp (reply->key,"BAD")) {
+ if ((flags & SE_NOLOCAL) ||
+ !mail_search_default (stream,charset,pgm,flags | SE_NOSERVER))
+ return NIL;
+ }
+ else if (!imap_OK (stream,reply)) {
+ mm_log (reply->text,ERROR);
+ return NIL;
+ }
+
+ /* can never pre-fetch with a short cache */
+ if ((k = imap_prefetch) && !(flags & (SE_NOPREFETCH | SE_UID)) &&
+ !stream->scache) { /* only if prefetching permitted */
+ t = LOCAL->tmp; /* build sequence in temporary buffer */
+ *t = '\0'; /* initially nothing */
+ /* search through mailbox */
+ for (i = 1; k && (i <= stream->nmsgs); ++i)
+ /* for searched messages with no envelope */
+ if ((elt = mail_elt (stream,i)) && elt->searched &&
+ !mail_elt (stream,i)->private.msg.env) {
+ /* prepend with comma if not first time */
+ if (LOCAL->tmp[0]) *t++ = ',';
+ sprintf (t,"%lu",j = i);/* output message number */
+ t += strlen (t); /* point at end of string */
+ k--; /* count one up */
+ /* search for possible end of range */
+ while (k && (i < stream->nmsgs) &&
+ (elt = mail_elt (stream,i+1))->searched &&
+ !elt->private.msg.env) i++,k--;
+ if (i != j) { /* if a range */
+ sprintf (t,":%lu",i); /* output delimiter and end of range */
+ t += strlen (t); /* point at end of string */
+ }
+ if ((t - LOCAL->tmp) > (IMAPTMPLEN - 50)) break;
+ }
+ if (LOCAL->tmp[0]) { /* anything to pre-fetch? */
+ /* pre-fetch envelopes for the first imap_prefetch number of messages */
+ if (!imap_OK (stream,reply =
+ imap_fetch (stream,t = cpystr (LOCAL->tmp),FT_NEEDENV +
+ ((flags & SE_NOHDRS) ? FT_NOHDRS : NIL) +
+ ((flags & SE_NEEDBODY) ? FT_NEEDBODY : NIL))))
+ mm_log (reply->text,ERROR);
+ fs_give ((void **) &t); /* flush copy of sequence */
+ }
+ }
+ return LONGT;
+}
+
/* IMAP send search program
* Accepts: MAIL stream
* reply tag
@@ -5663,6 +5900,7 @@ void imap_parse_capabilities (MAILSTREAM *stream,char *t)
else if (!compare_cstring (t,"CATENATE")) LOCAL->cap.catenate = T;
else if (!compare_cstring (t,"CONDSTORE")) LOCAL->cap.condstore = T;
else if (!compare_cstring (t,"ESEARCH")) LOCAL->cap.esearch = T;
+ else if (!compare_cstring (t,"X-GM-EXT-1")) LOCAL->cap.x_gm_ext1 = T;
else if (((t[0] == 'S') || (t[0] == 's')) &&
((t[1] == 'O') || (t[1] == 'o')) &&
((t[2] == 'R') || (t[2] == 'r')) &&
diff --git a/imap/src/c-client/imap4r1.h b/imap/src/c-client/imap4r1.h
index 8ee8a186..520b6562 100644
--- a/imap/src/c-client/imap4r1.h
+++ b/imap/src/c-client/imap4r1.h
@@ -87,6 +87,7 @@ typedef struct imap_cap {
unsigned int esearch : 1; /* server has ESEARCH (RFC 4731) */
unsigned int within : 1; /* server has WITHIN (RFC 5032) */
unsigned int extlevel; /* extension data level supported by server */
+ unsigned int x_gm_ext1:1; /* special extension for gmail server */
/* supported authenticators */
unsigned int auth : MAXAUTHENTICATORS;
THREADER *threader; /* list of threaders */
@@ -129,6 +130,11 @@ typedef struct imap_cap {
#define LEVELACL(stream) imap_cap (stream)->acl
+/* Has X-GM-EXT-1 extension */
+
+#define XGMEXT1(stream) imap_cap(stream)->x_gm_ext1
+
+
/* Has QUOTA extension */
#define LEVELQUOTA(stream) imap_cap (stream)->quota
diff --git a/imap/src/c-client/mail.c b/imap/src/c-client/mail.c
index 02519e5a..b18f7732 100644
--- a/imap/src/c-client/mail.c
+++ b/imap/src/c-client/mail.c
@@ -5990,6 +5990,7 @@ void mail_free_searchpgm (SEARCHPGM **pgm)
mail_free_stringlist (&(*pgm)->subject);
mail_free_stringlist (&(*pgm)->text);
mail_free_stringlist (&(*pgm)->to);
+ mail_free_stringlist (&(*pgm)->x_gm_ext1);
fs_give ((void **) pgm); /* return program to free storage */
}
}
diff --git a/imap/src/c-client/mail.h b/imap/src/c-client/mail.h
index 11ebdbc9..fc3f3862 100644
--- a/imap/src/c-client/mail.h
+++ b/imap/src/c-client/mail.h
@@ -996,6 +996,7 @@ SEARCHPGM { /* search program */
STRINGLIST *subject; /* text in subject */
STRINGLIST *text; /* text in headers and body */
STRINGLIST *to; /* to recipients */
+ STRINGLIST *x_gm_ext1; /* use X-GM-EXT-1 extension */
unsigned long larger; /* larger than this size */
unsigned long smaller; /* smaller than this size */
unsigned long older; /* older than this interval */