imap-send: add ability to list the available folders
Various IMAP servers have different ways to name common folders.
For example, the folder where all deleted messages are stored is often
named "[Gmail]/Trash" on Gmail servers, and "Deleted" on Outlook.
Similarly, the Drafts folder is simply named "Drafts" on Outlook, but
on Gmail it is named "[Gmail]/Drafts".
This commit adds a `--list` command to the `imap-send` tool that lists
the available folders on the IMAP server, allowing users to see
which folders are available and how they are named. A sample output
looks like this when run against a Gmail server:
Fetching the list of available folders...
* LIST (\HasNoChildren) "/" "INBOX"
* LIST (\HasChildren \Noselect) "/" "[Gmail]"
* LIST (\All \HasNoChildren) "/" "[Gmail]/All Mail"
* LIST (\Drafts \HasNoChildren) "/" "[Gmail]/Drafts"
* LIST (\HasNoChildren \Important) "/" "[Gmail]/Important"
* LIST (\HasNoChildren \Sent) "/" "[Gmail]/Sent Mail"
* LIST (\HasNoChildren \Junk) "/" "[Gmail]/Spam"
* LIST (\Flagged \HasNoChildren) "/" "[Gmail]/Starred"
* LIST (\HasNoChildren \Trash) "/" "[Gmail]/Trash"
For OpenSSL, this is achived by running the 'IMAP LIST' command and
parsing the response. This command is specified in RFC6154:
https://datatracker.ietf.org/doc/html/rfc6154#section-5.1
For libcurl, the example code published in the libcurl documentation
is used to implement this functionality:
https://curl.se/libcurl/c/imap-list.html
Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
committed by
Junio C Hamano
parent
3168514e6b
commit
067a91b03f
@@ -10,6 +10,7 @@ SYNOPSIS
|
|||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git imap-send' [-v] [-q] [--[no-]curl] [(--folder|-f) <folder>]
|
'git imap-send' [-v] [-q] [--[no-]curl] [(--folder|-f) <folder>]
|
||||||
|
'git imap-send' --list
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
@@ -54,6 +55,8 @@ OPTIONS
|
|||||||
using libcurl. Ignored if Git was built with the NO_OPENSSL option
|
using libcurl. Ignored if Git was built with the NO_OPENSSL option
|
||||||
set.
|
set.
|
||||||
|
|
||||||
|
--list::
|
||||||
|
Run the IMAP LIST command to output a list of all the folders present.
|
||||||
|
|
||||||
CONFIGURATION
|
CONFIGURATION
|
||||||
-------------
|
-------------
|
||||||
@@ -123,7 +126,8 @@ it. Alternatively, use OAuth2.0 authentication as described below.
|
|||||||
|
|
||||||
[NOTE]
|
[NOTE]
|
||||||
You might need to instead use: `folder = "[Google Mail]/Drafts"` if you get an error
|
You might need to instead use: `folder = "[Google Mail]/Drafts"` if you get an error
|
||||||
that the "Folder doesn't exist".
|
that the "Folder doesn't exist". You can also run `git imap-send --list` to get a
|
||||||
|
list of available folders.
|
||||||
|
|
||||||
[NOTE]
|
[NOTE]
|
||||||
If your Gmail account is set to another language than English, the name of the "Drafts"
|
If your Gmail account is set to another language than English, the name of the "Drafts"
|
||||||
|
|||||||
88
imap-send.c
88
imap-send.c
@@ -45,15 +45,21 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int verbosity;
|
static int verbosity;
|
||||||
|
static int list_folders;
|
||||||
static int use_curl = USE_CURL_DEFAULT;
|
static int use_curl = USE_CURL_DEFAULT;
|
||||||
static char *opt_folder;
|
static char *opt_folder;
|
||||||
|
|
||||||
static const char * const imap_send_usage[] = { "git imap-send [-v] [-q] [--[no-]curl] [(--folder|-f) <folder>] < <mbox>", NULL };
|
static char const * const imap_send_usage[] = {
|
||||||
|
N_("git imap-send [-v] [-q] [--[no-]curl] [(--folder|-f) <folder>] < <mbox>"),
|
||||||
|
"git imap-send --list",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
static struct option imap_send_options[] = {
|
static struct option imap_send_options[] = {
|
||||||
OPT__VERBOSITY(&verbosity),
|
OPT__VERBOSITY(&verbosity),
|
||||||
OPT_BOOL(0, "curl", &use_curl, "use libcurl to communicate with the IMAP server"),
|
OPT_BOOL(0, "curl", &use_curl, "use libcurl to communicate with the IMAP server"),
|
||||||
OPT_STRING('f', "folder", &opt_folder, "folder", "specify the IMAP folder"),
|
OPT_STRING('f', "folder", &opt_folder, "folder", "specify the IMAP folder"),
|
||||||
|
OPT_BOOL(0, "list", &list_folders, "list all folders on the IMAP server"),
|
||||||
OPT_END()
|
OPT_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -429,7 +435,7 @@ static int buffer_gets(struct imap_buffer *b, char **s)
|
|||||||
if (b->buf[b->offset + 1] == '\n') {
|
if (b->buf[b->offset + 1] == '\n') {
|
||||||
b->buf[b->offset] = 0; /* terminate the string */
|
b->buf[b->offset] = 0; /* terminate the string */
|
||||||
b->offset += 2; /* next line */
|
b->offset += 2; /* next line */
|
||||||
if (0 < verbosity)
|
if ((0 < verbosity) || (list_folders && strstr(*s, "* LIST")))
|
||||||
puts(*s);
|
puts(*s);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1572,6 +1578,26 @@ static int append_msgs_to_imap(struct imap_server_conf *server,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int list_imap_folders(struct imap_server_conf *server)
|
||||||
|
{
|
||||||
|
struct imap_store *ctx = imap_open_store(server, "INBOX");
|
||||||
|
if (!ctx) {
|
||||||
|
fprintf(stderr, "failed to connect to IMAP server\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Fetching the list of available folders...\n");
|
||||||
|
/* Issue the LIST command and print the results */
|
||||||
|
if (imap_exec(ctx, NULL, "LIST \"\" \"*\"") != RESP_OK) {
|
||||||
|
fprintf(stderr, "failed to list folders\n");
|
||||||
|
imap_close_store(ctx);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
imap_close_store(ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef USE_CURL_FOR_IMAP_SEND
|
#ifdef USE_CURL_FOR_IMAP_SEND
|
||||||
static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred)
|
static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred)
|
||||||
{
|
{
|
||||||
@@ -1605,11 +1631,13 @@ static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred)
|
|||||||
if (!path.len || path.buf[path.len - 1] != '/')
|
if (!path.len || path.buf[path.len - 1] != '/')
|
||||||
strbuf_addch(&path, '/');
|
strbuf_addch(&path, '/');
|
||||||
|
|
||||||
|
if (!list_folders) {
|
||||||
uri_encoded_folder = curl_easy_escape(curl, srvc->folder, 0);
|
uri_encoded_folder = curl_easy_escape(curl, srvc->folder, 0);
|
||||||
if (!uri_encoded_folder)
|
if (!uri_encoded_folder)
|
||||||
die("failed to encode server folder");
|
die("failed to encode server folder");
|
||||||
strbuf_addstr(&path, uri_encoded_folder);
|
strbuf_addstr(&path, uri_encoded_folder);
|
||||||
curl_free(uri_encoded_folder);
|
curl_free(uri_encoded_folder);
|
||||||
|
}
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, path.buf);
|
curl_easy_setopt(curl, CURLOPT_URL, path.buf);
|
||||||
strbuf_release(&path);
|
strbuf_release(&path);
|
||||||
@@ -1640,10 +1668,6 @@ static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred)
|
|||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, srvc->ssl_verify);
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, srvc->ssl_verify);
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, srvc->ssl_verify);
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, srvc->ssl_verify);
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer);
|
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
|
|
||||||
|
|
||||||
if (0 < verbosity || getenv("GIT_CURL_VERBOSE"))
|
if (0 < verbosity || getenv("GIT_CURL_VERBOSE"))
|
||||||
http_trace_curl_no_data();
|
http_trace_curl_no_data();
|
||||||
setup_curl_trace(curl);
|
setup_curl_trace(curl);
|
||||||
@@ -1662,6 +1686,10 @@ static int curl_append_msgs_to_imap(struct imap_server_conf *server,
|
|||||||
struct credential cred = CREDENTIAL_INIT;
|
struct credential cred = CREDENTIAL_INIT;
|
||||||
|
|
||||||
curl = setup_curl(server, &cred);
|
curl = setup_curl(server, &cred);
|
||||||
|
|
||||||
|
curl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_READDATA, &msgbuf);
|
curl_easy_setopt(curl, CURLOPT_READDATA, &msgbuf);
|
||||||
|
|
||||||
fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
|
fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
|
||||||
@@ -1707,6 +1735,31 @@ static int curl_append_msgs_to_imap(struct imap_server_conf *server,
|
|||||||
|
|
||||||
return res != CURLE_OK;
|
return res != CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int curl_list_imap_folders(struct imap_server_conf *server)
|
||||||
|
{
|
||||||
|
CURL *curl;
|
||||||
|
CURLcode res = CURLE_OK;
|
||||||
|
struct credential cred = CREDENTIAL_INIT;
|
||||||
|
|
||||||
|
fprintf(stderr, "Fetching the list of available folders...\n");
|
||||||
|
curl = setup_curl(server, &cred);
|
||||||
|
res = curl_easy_perform(curl);
|
||||||
|
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
curl_global_cleanup();
|
||||||
|
|
||||||
|
if (cred.username) {
|
||||||
|
if (res == CURLE_OK)
|
||||||
|
credential_approve(the_repository, &cred);
|
||||||
|
else if (res == CURLE_LOGIN_DENIED)
|
||||||
|
credential_reject(the_repository, &cred);
|
||||||
|
}
|
||||||
|
|
||||||
|
credential_clear(&cred);
|
||||||
|
|
||||||
|
return res != CURLE_OK;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int cmd_main(int argc, const char **argv)
|
int cmd_main(int argc, const char **argv)
|
||||||
@@ -1747,11 +1800,6 @@ int cmd_main(int argc, const char **argv)
|
|||||||
if (!server.port)
|
if (!server.port)
|
||||||
server.port = server.use_ssl ? 993 : 143;
|
server.port = server.use_ssl ? 993 : 143;
|
||||||
|
|
||||||
if (!server.folder) {
|
|
||||||
fprintf(stderr, "no imap store specified\n");
|
|
||||||
ret = 1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (!server.host) {
|
if (!server.host) {
|
||||||
if (!server.tunnel) {
|
if (!server.tunnel) {
|
||||||
fprintf(stderr, "no imap host specified\n");
|
fprintf(stderr, "no imap host specified\n");
|
||||||
@@ -1761,6 +1809,24 @@ int cmd_main(int argc, const char **argv)
|
|||||||
server.host = xstrdup("tunnel");
|
server.host = xstrdup("tunnel");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (list_folders) {
|
||||||
|
if (server.tunnel)
|
||||||
|
ret = list_imap_folders(&server);
|
||||||
|
#ifdef USE_CURL_FOR_IMAP_SEND
|
||||||
|
else if (use_curl)
|
||||||
|
ret = curl_list_imap_folders(&server);
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
ret = list_imap_folders(&server);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!server.folder) {
|
||||||
|
fprintf(stderr, "no imap store specified\n");
|
||||||
|
ret = 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* read the messages */
|
/* read the messages */
|
||||||
if (strbuf_read(&all_msgs, 0, 0) < 0) {
|
if (strbuf_read(&all_msgs, 0, 0) < 0) {
|
||||||
error_errno(_("could not read from stdin"));
|
error_errno(_("could not read from stdin"));
|
||||||
|
|||||||
Reference in New Issue
Block a user