Skip to content

Commit dd0d6d9

Browse files
committed
[RFC] IMAP NOTIFY support
await_notification()
1 parent 84990e9 commit dd0d6d9

7 files changed

Lines changed: 146 additions & 0 deletions

File tree

src/core.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ static int ifcore_rename(lua_State *lua);
3636
static int ifcore_subscribe(lua_State *lua);
3737
static int ifcore_unsubscribe(lua_State *lua);
3838
static int ifcore_idle(lua_State *lua);
39+
static int ifcore_notify(lua_State *lua);
3940

4041

4142
/* Lua imapfilter core library functions. */
@@ -77,6 +78,7 @@ static const luaL_Reg ifcorelib[] = {
7778
{ "store", ifcore_store },
7879
{ "copy", ifcore_copy },
7980
{ "idle", ifcore_idle },
81+
{ "notify", ifcore_notify },
8082
{ NULL, NULL }
8183
};
8284

@@ -1012,6 +1014,41 @@ ifcore_idle(lua_State *lua)
10121014
}
10131015

10141016

1017+
/*
1018+
* Core function to go to idle state.
1019+
*/
1020+
static int
1021+
ifcore_notify(lua_State *lua)
1022+
{
1023+
int r;
1024+
char *event;
1025+
1026+
event = NULL;
1027+
1028+
if (lua_gettop(lua) != 1)
1029+
luaL_error(lua, "wrong number of arguments");
1030+
luaL_checktype(lua, 1, LUA_TLIGHTUSERDATA);
1031+
1032+
r = request_notify((session *)(lua_topointer(lua, 1)), &event);
1033+
1034+
lua_pop(lua, 1);
1035+
1036+
if (r < 0)
1037+
return 0;
1038+
1039+
lua_pushboolean(lua, (r == STATUS_OK));
1040+
1041+
if (!event)
1042+
return 1;
1043+
1044+
lua_pushstring(lua, event);
1045+
1046+
xfree(event);
1047+
1048+
return 2;
1049+
}
1050+
1051+
10151052
/*
10161053
* Open imapfilter core library.
10171054
*/

src/imapfilter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#define CAPABILITY_XOAUTH2 0x10
3636
#define CAPABILITY_ENABLE 0x20
3737
#define CAPABILITY_UTF8 0x40
38+
#define CAPABILITY_NOTIFY 0x80
3839

3940
/* Status responses and response codes. */
4041
#define STATUS_BYE -2
@@ -184,6 +185,7 @@ int request_rename(session *ssn, const char *oldmbox, const char *newmbox);
184185
int request_subscribe(session *ssn, const char *mbox);
185186
int request_unsubscribe(session *ssn, const char *mbox);
186187
int request_idle(session *ssn, char **event);
188+
int request_notify(session *ssn, char **event);
187189

188190
/* response.c */
189191
int response_generic(session *ssn, int tag);
@@ -207,6 +209,7 @@ int response_fetchsize(session *ssn, int tag, char **size);
207209
int response_fetchstructure(session *ssn, int tag, char **structure);
208210
int response_fetchbody(session *ssn, int tag, char **body, size_t *len);
209211
int response_idle(session *ssn, int tag, char **event);
212+
int response_notify(session *ssn, char **event);
210213

211214
/* signal.c */
212215
void catch_signals(void);

src/mailbox.lua

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,24 @@ function Mailbox.enter_idle(self)
10801080
end
10811081

10821082

1083+
function Mailbox.await_notification(self)
1084+
if self._cached_select(self) ~= true then return false end
1085+
1086+
self._check_connection(self)
1087+
local r, event = ifcore.notify(self._account._account.session)
1088+
self._check_result(self, 'notify', r)
1089+
if r == false then return false end
1090+
1091+
if options.close == true then self._cached_close(self) end
1092+
1093+
if type(event) == 'string' then
1094+
return true, string.upper(event)
1095+
else
1096+
return true
1097+
end
1098+
end
1099+
1100+
10831101
Mailbox.open = _cached_select
10841102
Mailbox.close = _cached_close
10851103

src/request.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,3 +776,37 @@ request_idle(session *ssn, char **event)
776776

777777
return r;
778778
}
779+
780+
781+
int
782+
request_notify(session *ssn, char **event)
783+
{
784+
int t, r, ri;
785+
786+
debug("request_notify: capa:%x, status:%d\n\n",
787+
ssn->capabilities & CAPABILITY_NOTIFY,
788+
ssn->notify_active
789+
);
790+
791+
if (!(ssn->capabilities & CAPABILITY_NOTIFY))
792+
return STATUS_BAD;
793+
794+
if (!ssn->notify_active) {
795+
TRY(t = send_request(ssn, "NOTIFY SET (subtree INBOX (Messagenew))"));
796+
TRY(r = response_generic(ssn, t));
797+
if (r != STATUS_OK) {
798+
return r;
799+
}
800+
ssn->notify_active = 1;
801+
}
802+
803+
do {
804+
ri = 0;
805+
806+
TRY(ri = response_notify(ssn, event));
807+
if (ri == STATUS_TIMEOUT)
808+
request_noop(ssn);
809+
} while (ri == STATUS_TIMEOUT);
810+
811+
return r;
812+
}

src/response.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,8 @@ response_capability(session *ssn, int tag)
354354
ssn->capabilities |= CAPABILITY_ENABLE;
355355
if (xstrcasestr(s, "UTF8=ACCEPT"))
356356
ssn->capabilities |= CAPABILITY_UTF8;
357+
if (xstrcasestr(s, "NOTIFY"))
358+
ssn->capabilities |= CAPABILITY_NOTIFY;
357359

358360
xfree(s);
359361
}
@@ -892,3 +894,53 @@ response_idle(session *ssn, int tag, char **event)
892894

893895
return STATUS_UNTAGGED;
894896
}
897+
898+
899+
/*
900+
* Process the data that server sent due to IMAP NOTIFY client request.
901+
*/
902+
int
903+
response_notify(session *ssn, char **event)
904+
{
905+
regexp *re;
906+
ssize_t n;
907+
int eintr = 0;
908+
909+
re = &responses[RESPONSE_UNTAGGED];
910+
911+
for (;;) {
912+
buffer_reset(&ibuf);
913+
914+
do {
915+
buffer_check(&ibuf, ibuf.len + INPUT_BUF);
916+
n = receive_response(ssn, ibuf.data + ibuf.len,
917+
get_option_number("keepalive") * 60, 0, &eintr);
918+
if (n < 0) {
919+
if (eintr)
920+
return STATUS_INTERRUPT;
921+
else
922+
return STATUS_ERROR;
923+
}
924+
if (n == 0)
925+
return STATUS_TIMEOUT;
926+
ibuf.len += n;
927+
928+
if (check_bye(ibuf.data))
929+
return handle_bye(ssn);
930+
931+
} while (regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0));
932+
933+
verbose("S (%d): %s", ssn->socket, ibuf.data);
934+
935+
if (get_option_boolean("wakeonany"))
936+
break;
937+
if (!strncasecmp(ibuf.data + re->pmatch[1].rm_so,
938+
"STATUS", strlen("STATUS")))
939+
break;
940+
}
941+
942+
*event = xstrndup(ibuf.data + re->pmatch[1].rm_so,
943+
re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
944+
945+
return STATUS_UNTAGGED;
946+
}

src/session.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ session_init(session *ssn)
4242
ssn->ns.prefix = NULL;
4343
ssn->ns.delim = '\0';
4444
ssn->utf8 = 0;
45+
ssn->notify_active = 0;
4546
}
4647

4748

src/session.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ typedef struct session {
1717
char delim; /* Namespace delimiter. */
1818
} ns;
1919
int utf8; /* UTF8 enabled. */
20+
int notify_active; /* NOTIFY is active */
2021
} session;
2122

2223

0 commit comments

Comments
 (0)