mirror of
https://github.com/chatmail/core.git
synced 2026-04-02 05:22:14 +03:00
expose empty server functionality and test it (also introducing a new DC_EVENT_IMAP_FOLDER_EMPTIED event)
This commit is contained in:
@@ -1513,6 +1513,16 @@ char* dc_get_mime_headers (dc_context_t* context, uint32_t ms
|
||||
*/
|
||||
void dc_delete_msgs (dc_context_t* context, const uint32_t* msg_ids, int msg_cnt);
|
||||
|
||||
/**
|
||||
* Empty IMAP server folder: delete all messages.
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param context The context object as created by dc_context_new()
|
||||
* @param flags uint32_t with DC_EMPTY_* flags
|
||||
* @return None.
|
||||
*/
|
||||
void dc_empty_server (dc_context_t* context, const uint32_t flags);
|
||||
|
||||
|
||||
/**
|
||||
* Forward messages to another chat.
|
||||
@@ -3929,6 +3939,30 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup DC_EMPTY
|
||||
*
|
||||
* These constants configure emptying imap folders.
|
||||
*
|
||||
* @addtogroup DC_EMPTY
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Clear all mvbox messages.
|
||||
*/
|
||||
#define DC_EMPTY_MVBOX 0x01
|
||||
|
||||
/**
|
||||
* Clear all INBOX messages.
|
||||
*/
|
||||
#define DC_EMPTY_INBOX 0x02
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The library-user may write an informational string to the log.
|
||||
@@ -3995,6 +4029,16 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
*/
|
||||
#define DC_EVENT_IMAP_MESSAGE_MOVED 105
|
||||
|
||||
/**
|
||||
* Emitted when an IMAP folder was emptied.
|
||||
*
|
||||
* @param data1 0
|
||||
* @param data2 (const char*) folder name.
|
||||
* Must not be unref'd or modified and is valid only until the callback returns.
|
||||
* @return 0
|
||||
*/
|
||||
#define DC_EVENT_IMAP_FOLDER_EMPTIED 106
|
||||
|
||||
/**
|
||||
* Emitted when a new blob file was successfully written
|
||||
*
|
||||
|
||||
@@ -130,6 +130,7 @@ impl ContextWrapper {
|
||||
| Event::SmtpMessageSent(msg)
|
||||
| Event::ImapMessageDeleted(msg)
|
||||
| Event::ImapMessageMoved(msg)
|
||||
| Event::ImapFolderEmptied(msg)
|
||||
| Event::NewBlobFile(msg)
|
||||
| Event::DeletedBlobFile(msg)
|
||||
| Event::Warning(msg)
|
||||
@@ -1286,6 +1287,18 @@ pub unsafe extern "C" fn dc_delete_msgs(
|
||||
.unwrap_or(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_empty_server(context: *mut dc_context_t, flags: u32) {
|
||||
if context.is_null() || flags == 0 {
|
||||
eprintln!("ignoring careless call to dc_empty_server()");
|
||||
return;
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| message::dc_empty_server(ctx, flags))
|
||||
.unwrap_or(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_forward_msgs(
|
||||
context: *mut dc_context_t,
|
||||
|
||||
@@ -404,6 +404,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
checkqr <qr-content>\n\
|
||||
event <event-id to test>\n\
|
||||
fileinfo <file>\n\
|
||||
emptyserver <flags> (1=MVBOX 2=INBOX)\n\
|
||||
clear -- clear screen\n\
|
||||
exit or quit\n\
|
||||
============================================="
|
||||
@@ -976,6 +977,11 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
bail!("Command failed.");
|
||||
}
|
||||
}
|
||||
"emptyserver" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <flags> missing");
|
||||
|
||||
message::dc_empty_server(context, arg1.parse()?);
|
||||
}
|
||||
"" => (),
|
||||
_ => bail!("Unknown command: \"{}\" type ? for help.", arg0),
|
||||
}
|
||||
|
||||
@@ -135,6 +135,17 @@ class Account(object):
|
||||
if not self.is_configured():
|
||||
raise ValueError("need to configure first")
|
||||
|
||||
def empty_server_folders(self, inbox=False, mvbox=False):
|
||||
""" empty server folders. """
|
||||
flags = 0
|
||||
if inbox:
|
||||
flags |= const.DC_EMPTY_INBOX
|
||||
if mvbox:
|
||||
flags |= const.DC_EMPTY_MVBOX
|
||||
if not flags:
|
||||
raise ValueError("no flags set")
|
||||
lib.dc_empty_server(self._dc_context, flags)
|
||||
|
||||
def get_infostring(self):
|
||||
""" return info of the configured account. """
|
||||
self.check_is_configured()
|
||||
|
||||
@@ -69,12 +69,15 @@ DC_CERTCK_AUTO = 0
|
||||
DC_CERTCK_STRICT = 1
|
||||
DC_CERTCK_ACCEPT_INVALID_HOSTNAMES = 2
|
||||
DC_CERTCK_ACCEPT_INVALID_CERTIFICATES = 3
|
||||
DC_EMPTY_MVBOX = 0x01
|
||||
DC_EMPTY_INBOX = 0x02
|
||||
DC_EVENT_INFO = 100
|
||||
DC_EVENT_SMTP_CONNECTED = 101
|
||||
DC_EVENT_IMAP_CONNECTED = 102
|
||||
DC_EVENT_SMTP_MESSAGE_SENT = 103
|
||||
DC_EVENT_IMAP_MESSAGE_DELETED = 104
|
||||
DC_EVENT_IMAP_MESSAGE_MOVED = 105
|
||||
DC_EVENT_IMAP_FOLDER_EMPTIED = 106
|
||||
DC_EVENT_NEW_BLOB_FILE = 150
|
||||
DC_EVENT_DELETED_BLOB_FILE = 151
|
||||
DC_EVENT_WARNING = 300
|
||||
@@ -151,7 +154,7 @@ DC_STR_COUNT = 67
|
||||
|
||||
|
||||
def read_event_defines(f):
|
||||
rex = re.compile(r'#define\s+((?:DC_EVENT|DC_QR|DC_MSG|DC_LP|DC_CERTCK|DC_STATE|DC_STR|'
|
||||
rex = re.compile(r'#define\s+((?:DC_EVENT|DC_QR|DC_MSG|DC_LP|DC_EMPTY|DC_CERTCK|DC_STATE|DC_STR|'
|
||||
r'DC_CONTACT_ID|DC_GCL|DC_CHAT|DC_PROVIDER)_\S+)\s+([x\d]+).*')
|
||||
for line in f:
|
||||
m = rex.match(line)
|
||||
|
||||
@@ -180,6 +180,12 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig):
|
||||
ac.start_threads(mvbox=mvbox, sentbox=sentbox)
|
||||
return ac
|
||||
|
||||
def get_one_online_account(self):
|
||||
ac1 = self.get_online_configuring_account()
|
||||
wait_successful_IMAP_SMTP_connection(ac1)
|
||||
wait_configuration_progress(ac1, 1000)
|
||||
return ac1
|
||||
|
||||
def get_two_online_accounts(self):
|
||||
ac1 = self.get_online_configuring_account()
|
||||
ac2 = self.get_online_configuring_account()
|
||||
|
||||
@@ -493,6 +493,18 @@ class TestOnlineAccount:
|
||||
assert msg_in.text == "message2"
|
||||
assert msg_in.is_forwarded()
|
||||
|
||||
def test_send_self_message_and_empty_folder(self, acfactory, lp):
|
||||
ac1 = acfactory.get_one_online_account()
|
||||
lp.sec("ac1: create self chat")
|
||||
chat = ac1.create_chat_by_contact(ac1.get_self_contact())
|
||||
chat.send_text("hello")
|
||||
ac1._evlogger.get_matching("DC_EVENT_SMTP_MESSAGE_SENT")
|
||||
ac1.empty_server_folders(inbox=True, mvbox=True)
|
||||
ev = ac1._evlogger.get_matching("DC_EVENT_IMAP_FOLDER_EMPTIED")
|
||||
assert ev[2] == "DeltaChat"
|
||||
ev = ac1._evlogger.get_matching("DC_EVENT_IMAP_FOLDER_EMPTIED")
|
||||
assert ev[2] == "INBOX"
|
||||
|
||||
def test_send_and_receive_message_markseen(self, acfactory, lp):
|
||||
ac1, ac2 = acfactory.get_two_online_accounts()
|
||||
|
||||
|
||||
@@ -54,6 +54,12 @@ pub enum Event {
|
||||
#[strum(props(id = "105"))]
|
||||
ImapMessageMoved(String),
|
||||
|
||||
/// Emitted when an IMAP folder was emptied
|
||||
///
|
||||
/// @return 0
|
||||
#[strum(props(id = "106"))]
|
||||
ImapFolderEmptied(String),
|
||||
|
||||
/// Emitted when an new file in the $BLOBDIR was created
|
||||
///
|
||||
/// @return 0
|
||||
|
||||
14
src/imap.rs
14
src/imap.rs
@@ -651,7 +651,8 @@ impl Imap {
|
||||
}
|
||||
|
||||
// deselect existing folder, if needed (it's also done implicitly by SELECT, however, without EXPUNGE then)
|
||||
if self.config.read().unwrap().selected_folder_needs_expunge {
|
||||
let needs_expunge = { self.config.read().unwrap().selected_folder_needs_expunge };
|
||||
if needs_expunge {
|
||||
if let Some(ref folder) = self.config.read().unwrap().selected_folder {
|
||||
info!(context, "Expunge messages in \"{}\".", folder);
|
||||
|
||||
@@ -659,16 +660,19 @@ impl Imap {
|
||||
// https://tools.ietf.org/html/rfc3501#section-6.4.2
|
||||
if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||
match session.close() {
|
||||
Ok(_) => {}
|
||||
Ok(_) => {
|
||||
info!(context, "close/expunge succeeded");
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(context, "failed to close session: {:?}", err);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
self.config.write().unwrap().selected_folder_needs_expunge = true;
|
||||
}
|
||||
self.config.write().unwrap().selected_folder_needs_expunge = false;
|
||||
}
|
||||
|
||||
// select new folder
|
||||
@@ -1510,10 +1514,10 @@ impl Imap {
|
||||
if self.select_folder::<String>(context, None) == 0 {
|
||||
warn!(
|
||||
context,
|
||||
"could not perform expunge on empty folder {}", folder
|
||||
"could not perform expunge on empty-marked folder {}", folder
|
||||
);
|
||||
} else {
|
||||
info!(context, "Emptying folder '{}' done.", folder);
|
||||
emit_event!(context, Event::ImapFolderEmptied(folder.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1276,6 +1276,12 @@ pub fn update_server_uid(
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn dc_empty_server(context: &Context, flags: u32) {
|
||||
job_kill_action(context, Action::EmptyServer);
|
||||
job_add(context, Action::EmptyServer, flags as i32, Params::new(), 0);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user