Skip to content

Commit e508f2d

Browse files
committed
imap: support setting $Forwarded
midb recognized a Forwarded flag (W), but this was never exposed via midb_agent, and imap_parser.c never did anything with it either. Implement it. Fixes: gromox-0~666
1 parent 5c4acb2 commit e508f2d

File tree

6 files changed

+36
-8
lines changed

6 files changed

+36
-8
lines changed

doc/changelog.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Enhancements:
77
(if not running grommunio nginx config in front)
88
* oxcical: try to handle ICS files with missing VTIMEZONE blocks
99
* oxcical: support YEARLY recurrences with BYDAY without BYSETPOS
10+
* imap: offer $Forwarded keyword for APPEND/STORE commands
1011

1112
Fixes:
1213

@@ -16,6 +17,8 @@ Fixes:
1617
exported to iCal
1718
* midb, imap: make EXPUNGE synchronous so that old UIDs don't reappear in
1819
a subsequent FETCH
20+
* midb: respect setting \Deleted, \Answered, \Flagged during APPEND
21+
1922

2023

2124
Gromox 2.46 (2025-05-28)

include/gromox/midb.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ enum {
4343
};
4444

4545
enum midb_flag : char {
46+
/* On-wire text protocol */
4647
answered = 'A',
4748
deleted = 'D',
4849
flagged = 'F',

include/gromox/midb_agent.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ enum {
2020
FLAG_DELETED = 0x8,
2121
FLAG_SEEN = 0x10,
2222
FLAG_DRAFT = 0x20,
23+
FLAG_FORWARDED= 0x40,
24+
25+
/* mnemonics */
26+
FLAG_ALL = 0x4F,
27+
28+
/* internal */
2329
FLAG_LOADED = 0x80,
2430
};
2531

mra/imap/cmd.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,8 @@ static std::string icp_convert_flags_string(int flag_bits)
450450
out += "\\Seen ";
451451
if (flag_bits & FLAG_DRAFT)
452452
out += "\\Draft ";
453+
if (flag_bits & FLAG_FORWARDED)
454+
out += "$Forwarded ";
453455
if (out.size() > 1)
454456
/* There is more than just the opening parenthesis, so there must be a space */
455457
out.back() = ')';
@@ -956,8 +958,7 @@ static void icp_store_flags(const char *cmd, const std::string &mid,
956958
if (0 == strcasecmp(cmd, "FLAGS") ||
957959
0 == strcasecmp(cmd, "FLAGS.SILENT")) {
958960
midb_agent::unset_flags(pcontext->maildir, pcontext->selected_folder,
959-
mid, FLAG_ANSWERED | FLAG_FLAGGED | FLAG_DELETED |
960-
FLAG_SEEN | FLAG_DRAFT | FLAG_RECENT, nullptr, &errnum);
961+
mid, FLAG_ALL, nullptr, &errnum);
961962
midb_agent::set_flags(pcontext->maildir, pcontext->selected_folder,
962963
mid, flag_bits, nullptr, &errnum);
963964
if (0 == strcasecmp(cmd, "FLAGS")) {
@@ -1129,14 +1130,15 @@ static void icp_convert_folderlist(std::vector<enum_folder_t> &pfile) try
11291130
}
11301131

11311132
static std::string flagbits_to_s(bool seen, bool answ, bool flagged, bool draft,
1132-
bool del)
1133+
bool del, bool fwd)
11331134
{
11341135
std::string s = "(";
11351136
if (seen) s += midb_flag::seen;
11361137
if (answ) s += midb_flag::answered;
11371138
if (flagged) s += midb_flag::flagged;
11381139
if (draft) s += midb_flag::unsent;
11391140
if (del) s += midb_flag::deleted;
1141+
if (fwd) s += midb_flag::forwarded;
11401142
s += ')';
11411143
return s;
11421144
}
@@ -1513,12 +1515,12 @@ static int icp_selex(int argc, char **argv, imap_context &ctx, bool readonly) tr
15131515
auto buf = fmt::format(
15141516
"* {} EXISTS\r\n"
15151517
"* {} RECENT\r\n"
1516-
"* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)\r\n"
1518+
"* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft $Forwarded)\r\n"
15171519
"* OK {}\r\n",
15181520
pcontext->contents.n_exists(),
15191521
pcontext->contents.n_recent, readonly ?
15201522
"[PERMANENTFLAGS ()] no permanent flags permitted" :
1521-
"[PERMANENTFLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)] limited");
1523+
"[PERMANENTFLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft $Forwarded)] limited");
15221524
if (pcontext->contents.firstunseen != 0)
15231525
buf += fmt::format("* OK [UNSEEN {}] message {} is first unseen\r\n",
15241526
pcontext->contents.firstunseen,
@@ -2003,7 +2005,9 @@ int icp_append(int argc, char **argv, imap_context &ctx) try
20032005
std::any_of(&temp_argv[0], &temp_argv[temp_argc],
20042006
[](const char *s) { return strcasecmp(s, "\\Draft") == 0; }),
20052007
std::any_of(&temp_argv[0], &temp_argv[temp_argc],
2006-
[](const char *s) { return strcasecmp(s, "\\Deleted") == 0; }));
2008+
[](const char *s) { return strcasecmp(s, "\\Deleted") == 0; }),
2009+
std::any_of(&temp_argv[0], &temp_argv[temp_argc],
2010+
[](const char *s) { return strcasecmp(s, "$Forwarded") == 0; }));
20072011
}
20082012
std::string mid_string;
20092013
time_t tmp_time = time(nullptr);
@@ -2066,7 +2070,7 @@ int icp_append(int argc, char **argv, imap_context &ctx) try
20662070

20672071
static inline bool append_allowed_flag_name(const char *flag)
20682072
{
2069-
static constexpr const char *names[] = {"\\Answered", "\\Flagged", "\\Seen", "\\Draft", "\\Deleted"};
2073+
static constexpr const char *names[] = {"\\Answered", "\\Flagged", "\\Seen", "\\Draft", "\\Deleted", "$Forwarded"};
20702074
for (auto s : names)
20712075
if (strcasecmp(flag, s) == 0)
20722076
return true;
@@ -2119,7 +2123,8 @@ static int icp_long_append_begin2(int argc, char **argv, imap_context &ctx) try
21192123
strcasestr(str_flags, "\\Answered") != nullptr,
21202124
strcasestr(str_flags, "\\Flagged") != nullptr,
21212125
strcasestr(str_flags, "\\Draft") != nullptr,
2122-
strcasestr(str_flags, "\\Deleted") != nullptr);
2126+
strcasestr(str_flags, "\\Deleted") != nullptr,
2127+
strcasestr(str_flags, "$Forwarded") != nullptr);
21232128
if (str_received == nullptr || *str_received == '\0' ||
21242129
!icp_convert_imaptime(str_received, &ctx.append_time))
21252130
ctx.append_time = time(nullptr);
@@ -2498,6 +2503,8 @@ int icp_store(int argc, char **argv, imap_context &ctx)
24982503
flag_bits |= FLAG_DRAFT;
24992504
else if (strcasecmp(temp_argv[i], "\\Recent") == 0)
25002505
flag_bits |= FLAG_RECENT;
2506+
else if (strcasecmp(temp_argv[i], "$Forwarded") == 0)
2507+
flag_bits |= FLAG_FORWARDED;
25012508
else
25022509
return 1807;
25032510
}
@@ -2759,6 +2766,8 @@ int icp_uid_store(int argc, char **argv, imap_context &ctx)
27592766
flag_bits |= FLAG_DRAFT;
27602767
else if (strcasecmp(temp_argv[i], "\\Recent") == 0)
27612768
flag_bits |= FLAG_RECENT;
2769+
else if (strcasecmp(temp_argv[i], "$Forwarded") == 0)
2770+
flag_bits |= FLAG_FORWARDED;
27622771
else
27632772
return 1807;
27642773
}

mra/imap/parser.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,6 +1343,11 @@ void imap_parser_echo_modify(imap_context *pcontext, STREAM *pstream)
13431343
buff[outlen++] = ' ';
13441344
outlen += gx_snprintf(&buff[outlen], std::size(buff) - outlen, "\\Draft");
13451345
}
1346+
if (flag_bits & FLAG_FORWARDED) {
1347+
if (b_first)
1348+
buff[outlen++] = ' ';
1349+
outlen += gx_snprintf(&buff[outlen], std::size(buff) - outlen, "$Forwarded");
1350+
}
13461351
outlen += gx_snprintf(&buff[outlen], std::size(buff) - outlen, "))\r\n");
13471352
if (pstream == nullptr)
13481353
pcontext->connection.write(buff, outlen);

mra/midb_agent.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,7 @@ static unsigned int s_to_flagbits(std::string_view s)
10911091
if (s.find(midb_flag::deleted) != s.npos) fl |= FLAG_DELETED;
10921092
if (s.find(midb_flag::seen) != s.npos) fl |= FLAG_SEEN;
10931093
if (s.find(midb_flag::recent) != s.npos) fl |= FLAG_RECENT;
1094+
if (s.find(midb_flag::forwarded) != s.npos)fl |= FLAG_FORWARDED;
10941095
return fl;
10951096
}
10961097

@@ -1103,6 +1104,7 @@ static std::string flagbits_to_s(unsigned int v)
11031104
if (v & FLAG_DELETED) s += midb_flag::deleted;
11041105
if (v & FLAG_SEEN) s += midb_flag::seen;
11051106
if (v & FLAG_RECENT) s += midb_flag::recent;
1107+
if (v & FLAG_FORWARDED)s += midb_flag::forwarded;
11061108
return s;
11071109
}
11081110

@@ -1139,6 +1141,8 @@ static unsigned int di_to_flagbits(const Json::Value &jv)
11391141
fl |= FLAG_SEEN;
11401142
if (jv.isMember("recent") && (v = jv["recent"].asUInt()) != 0)
11411143
fl |= FLAG_RECENT;
1144+
if (jv.isMember("forwarded") && (v = jv["forwarded"].asUInt()) != 0)
1145+
fl |= FLAG_FORWARDED;
11421146
return fl;
11431147
}
11441148

0 commit comments

Comments
 (0)