Reworked TrashMonitor to watch actual trash folder(s).

It was still monitoring /boot/home/Desktop/Trash folder,
which don't exists anymore.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39803 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Philippe Houdoin
2010-12-10 13:53:43 +00:00
parent 021ddf0c3b
commit dfc6cf0159
+156 -65
View File
@@ -4,22 +4,24 @@
*/ */
#include <String.h>
#include <Alert.h>
#include <Query.h>
#include <VolumeRoster.h>
#include <StringList.h>
#include <E-mail.h>
#include <NodeInfo.h>
#include <Directory.h>
#include <NodeMonitor.h>
#include <Node.h>
#include <stdio.h> #include <stdio.h>
#include <fs_attr.h> #include <fs_attr.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <Alert.h>
#include <Directory.h>
#include <FindDirectory.h>
#include <Query.h>
#include <E-mail.h>
#include <Node.h>
#include <NodeInfo.h>
#include <NodeMonitor.h>
#include <Path.h>
#include <String.h>
#include <StringList.h>
#include <VolumeRoster.h>
#include <MDRLanguage.h> #include <MDRLanguage.h>
class BMailProtocol; class BMailProtocol;
@@ -40,7 +42,7 @@ class ManifestAdder : public BMailChainCallback {
(**uids_on_disk) += uid; (**uids_on_disk) += uid;
} }
} }
private: private:
BStringList *manifest,**uids_on_disk; BStringList *manifest,**uids_on_disk;
const char *uid; const char *uid;
@@ -50,7 +52,7 @@ class MessageDeletion : public BMailChainCallback {
public: public:
MessageDeletion(BMailProtocol *home, const char *uid, BEntry *io_entry, bool delete_anyway); MessageDeletion(BMailProtocol *home, const char *uid, BEntry *io_entry, bool delete_anyway);
virtual void Callback(status_t result); virtual void Callback(status_t result);
private: private:
BMailProtocol *us; BMailProtocol *us;
bool always; bool always;
@@ -76,6 +78,7 @@ BMailProtocol::error_alert(const char *process, status_t error)
namespace { namespace {
class DeleteHandler : public BHandler { class DeleteHandler : public BHandler {
public: public:
DeleteHandler(BMailProtocol *a) DeleteHandler(BMailProtocol *a)
@@ -96,64 +99,152 @@ class DeleteHandler : public BHandler {
BMailProtocol *us; BMailProtocol *us;
}; };
class TrashMonitor : public BHandler { class TrashMonitor : public BHandler {
public: public:
TrashMonitor(BMailProtocol *a, int32 chain_id) TrashMonitor(BMailProtocol *a, int32 chain_id)
: us(a), trash("/boot/home/Desktop/Trash"), messages_for_us(0), id(chain_id) : us(a), messages_for_us(0), id(chain_id)
{ {
} }
~TrashMonitor()
{
stop_watching(this);
}
void MessageReceived(BMessage *msg) void MessageReceived(BMessage *msg)
{ {
if (msg->what == 'INIT') { if (msg->what == 'INIT') {
node_ref to_watch; BVolumeRoster volumes;
trash.GetNodeRef(&to_watch); BVolume volume;
watch_node(&to_watch,B_WATCH_DIRECTORY,this); while (volumes.GetNextVolume(&volume) == B_OK) {
BPath trashPath;
if (find_directory(B_TRASH_DIRECTORY, &trashPath,
false, &volume) == B_OK) {
// watch this trash directory
BNode node(trashPath.Path());
node_ref to_watch;
node.GetNodeRef(&to_watch);
watch_node(&to_watch, B_WATCH_DIRECTORY, this);
}
}
// Also watch for new volume
watch_node(NULL, B_WATCH_MOUNT, this);
return; return;
} }
if ((msg->what == B_NODE_MONITOR) && (us->InitCheck() == B_OK)) {
int32 opcode; if (msg->what != B_NODE_MONITOR || (us->InitCheck() != B_OK))
if (msg->FindInt32("opcode",&opcode) < B_OK) return;
int32 opcode;
if (msg->FindInt32("opcode",&opcode) < B_OK)
return;
if (opcode == B_DEVICE_MOUNTED) {
dev_t device;
if (msg->FindInt32("new device", &device) != B_OK)
return; return;
BVolume volume(device);
if (opcode == B_ENTRY_MOVED) { BPath trashPath;
int64 node(msg->FindInt64("to directory")); if (find_directory(B_TRASH_DIRECTORY, &trashPath,
dev_t device(msg->FindInt32("device")); false, &volume) == B_OK) {
node_ref item_ref; // watch also this new volume's trash directory
item_ref.node = node; BNode node(trashPath.Path());
item_ref.device = device; node_ref to_watch;
node.GetNodeRef(&to_watch);
BDirectory moved_to(&item_ref); watch_node(&to_watch, B_WATCH_DIRECTORY, this);
BNode trash_item(&moved_to,msg->FindString("name"));
int32 chain;
if (trash_item.ReadAttr("MAIL:chain",B_INT32_TYPE,0,&chain,sizeof(chain)) < B_OK)
return;
if (chain == id)
messages_for_us += (moved_to == trash) ? 1 : -1;
} }
return;
if (messages_for_us < 0) }
messages_for_us = 0; // Guard against weirdness
if (opcode == B_ENTRY_MOVED) {
if (trash.CountEntries() == 0) { entry_ref entry;
if (messages_for_us > 0) const char* name;
us->CheckForDeletedMessages(); msg->FindInt64("to directory", &entry.directory);
msg->FindInt32("device", &entry.device);
msg->FindString("name", &name);
entry.set_name(name);
BNode node(&entry);
int32 chain;
// check it's a mail
if (node.ReadAttr("MAIL:chain",B_INT32_TYPE,0,&chain,sizeof(chain)) < B_OK)
return;
// check it's a mail for us
if (chain != id)
return;
// check if it was moved to trash
bool moved_to_trash = false;
BPath trashPath;
BPath entryPath(&entry);
BVolumeRoster volumes;
BVolume volume;
while (volumes.GetNextVolume(&volume) == B_OK) {
BPath trashPath;
if (find_directory(B_TRASH_DIRECTORY, &trashPath,
false, &volume) != B_OK) {
continue;
}
if (strncmp(entryPath.Path(), trashPath.Path(),
strlen(trashPath.Path())) == 0) {
moved_to_trash = true;
break;
}
}
messages_for_us += (moved_to_trash) ? 1 : -1;
if (messages_for_us < 0) {
// Guard against weirdness
messages_for_us = 0; messages_for_us = 0;
return;
} }
} }
if (opcode != B_ENTRY_REMOVED)
return;
// Check if this (trash) entry removal made one trash now empty
bool someTrashIsEmpty = false;
BVolumeRoster volumes;
BVolume volume;
while (volumes.GetNextVolume(&volume) == B_OK) {
BPath trashPath;
if (find_directory(B_TRASH_DIRECTORY, &trashPath,
false, &volume) != B_OK) {
continue;
}
BDirectory trash(trashPath.Path());
if (trash.CountEntries() == 0) {
someTrashIsEmpty = true;
break;
}
}
if (someTrashIsEmpty) {
// One trash is empty, check for deleted messages
if (messages_for_us > 0)
us->CheckForDeletedMessages();
messages_for_us = 0;
}
} }
private: private:
BMailProtocol *us; BMailProtocol *us;
BDirectory trash;
int32 messages_for_us; int32 messages_for_us;
int32 id; int32 id;
}; };
} // unnamed namspace } // unnamed namespace
// #pragma mark BMailProtocol
BMailProtocol::BMailProtocol(BMessage *settings, BMailChainRunner *run) BMailProtocol::BMailProtocol(BMessage *settings, BMailChainRunner *run)
: BMailFilter(settings), : BMailFilter(settings),
@@ -163,17 +254,17 @@ BMailProtocol::BMailProtocol(BMessage *settings, BMailChainRunner *run)
BMailProtocol::settings = settings; BMailProtocol::settings = settings;
manifest = new BStringList; manifest = new BStringList;
{ {
BString attr_name = "MAIL:"; BString attr_name = "MAIL:";
attr_name << runner->Chain()->ID() << ":manifest"; //--- In case someone puts multiple accounts in the same directory attr_name << runner->Chain()->ID() << ":manifest"; //--- In case someone puts multiple accounts in the same directory
if (runner->Chain()->MetaData()->HasString("path")) { if (runner->Chain()->MetaData()->HasString("path")) {
BNode node(runner->Chain()->MetaData()->FindString("path")); BNode node(runner->Chain()->MetaData()->FindString("path"));
if (node.InitCheck() >= B_OK) { if (node.InitCheck() >= B_OK) {
// We already have a directory so we can try to read metadata // We already have a directory so we can try to read metadata
// from it. Note that it is normal for this directory not to // from it. Note that it is normal for this directory not to
// be founf on the first run as it will be later created by // be found on the first run as it will be later created by
// the INBOX system filter. // the INBOX system filter.
attr_info info; attr_info info;
if (node.GetAttrInfo(attr_name.String(),&info) < B_OK) { if (node.GetAttrInfo(attr_name.String(),&info) < B_OK) {
@@ -190,14 +281,14 @@ BMailProtocol::BMailProtocol(BMessage *settings, BMailChainRunner *run)
} }
} else runner->ShowError("Error while reading account manifest: no destination directory exists."); } else runner->ShowError("Error while reading account manifest: no destination directory exists.");
} }
uids_on_disk = new BStringList; uids_on_disk = new BStringList;
BVolumeRoster volumes; BVolumeRoster volumes;
BVolume volume; BVolume volume;
while (volumes.GetNextVolume(&volume) == B_OK) { while (volumes.GetNextVolume(&volume) == B_OK) {
BQuery fido; BQuery fido;
entry_ref entry; entry_ref entry;
fido.SetVolume(&volume); fido.SetVolume(&volume);
fido.PushAttr("MAIL:chain"); fido.PushAttr("MAIL:chain");
fido.PushInt32(settings->FindInt32("chain")); fido.PushInt32(settings->FindInt32("chain"));
@@ -213,21 +304,21 @@ BMailProtocol::BMailProtocol(BMessage *settings, BMailChainRunner *run)
fido.PushOp(B_AND); fido.PushOp(B_AND);
} }
fido.Fetch(); fido.Fetch();
BString uid; BString uid;
while (fido.GetNextRef(&entry) == B_OK) { while (fido.GetNextRef(&entry) == B_OK) {
BNode(&entry).ReadAttrString("MAIL:unique_id",&uid); BNode(&entry).ReadAttrString("MAIL:unique_id",&uid);
uids_on_disk->AddItem(uid.String()); uids_on_disk->AddItem(uid.String());
} }
} }
(*manifest) |= (*uids_on_disk); (*manifest) |= (*uids_on_disk);
if (!settings->FindBool("login_and_do_nothing_else_of_any_importance")) { if (!settings->FindBool("login_and_do_nothing_else_of_any_importance")) {
DeleteHandler *h = new DeleteHandler(this); DeleteHandler *h = new DeleteHandler(this);
runner->AddHandler(h); runner->AddHandler(h);
runner->PostMessage('DELE',h); runner->PostMessage('DELE',h);
trash_monitor = new TrashMonitor(this,runner->Chain()->ID()); trash_monitor = new TrashMonitor(this,runner->Chain()->ID());
runner->AddHandler(trash_monitor); runner->AddHandler(trash_monitor);
runner->PostMessage('INIT',trash_monitor); runner->PostMessage('INIT',trash_monitor);
@@ -269,7 +360,7 @@ BMailProtocol::~BMailProtocol()
for (int32 i = 0; i < (a)->CountItems(); i++)\ for (int32 i = 0; i < (a)->CountItems(); i++)\
puts((a)->ItemAt(i)); \ puts((a)->ItemAt(i)); \
puts("Done\n"); puts("Done\n");
status_t status_t
BMailProtocol::ProcessMailMessage(BPositionIO **io_message, BEntry *io_entry, BMailProtocol::ProcessMailMessage(BPositionIO **io_message, BEntry *io_entry,
BMessage *io_headers, BPath *io_folder, const char *io_uid) BMessage *io_headers, BPath *io_folder, const char *io_uid)
@@ -278,7 +369,7 @@ BMailProtocol::ProcessMailMessage(BPositionIO **io_message, BEntry *io_entry,
if (io_uid == NULL) if (io_uid == NULL)
return B_ERROR; return B_ERROR;
error = GetMessage(io_uid, io_message, io_headers, io_folder); error = GetMessage(io_uid, io_message, io_headers, io_folder);
if (error < B_OK) { if (error < B_OK) {
if (error != B_MAIL_END_FETCH) { if (error != B_MAIL_END_FETCH) {
@@ -306,16 +397,16 @@ void BMailProtocol::CheckForDeletedMessages() {
if (((settings->FindBool("delete_remote_when_local")) || !(settings->FindBool("leave_mail_on_server"))) && (manifest->CountItems() > 0)) { if (((settings->FindBool("delete_remote_when_local")) || !(settings->FindBool("leave_mail_on_server"))) && (manifest->CountItems() > 0)) {
BStringList to_delete; BStringList to_delete;
if (uids_on_disk == NULL) { if (uids_on_disk == NULL) {
BStringList query_contents; BStringList query_contents;
BVolumeRoster volumes; BVolumeRoster volumes;
BVolume volume; BVolume volume;
while (volumes.GetNextVolume(&volume) == B_OK) { while (volumes.GetNextVolume(&volume) == B_OK) {
BQuery fido; BQuery fido;
entry_ref entry; entry_ref entry;
fido.SetVolume(&volume); fido.SetVolume(&volume);
fido.PushAttr("MAIL:chain"); fido.PushAttr("MAIL:chain");
fido.PushInt32(settings->FindInt32("chain")); fido.PushInt32(settings->FindInt32("chain"));
@@ -325,24 +416,24 @@ void BMailProtocol::CheckForDeletedMessages() {
fido.PushOp(B_EQ); fido.PushOp(B_EQ);
fido.PushOp(B_OR); fido.PushOp(B_OR);
fido.Fetch(); fido.Fetch();
BString uid; BString uid;
while (fido.GetNextRef(&entry) == B_OK) { while (fido.GetNextRef(&entry) == B_OK) {
BNode(&entry).ReadAttrString("MAIL:unique_id",&uid); BNode(&entry).ReadAttrString("MAIL:unique_id",&uid);
query_contents.AddItem(uid.String()); query_contents.AddItem(uid.String());
} }
} }
query_contents.NotHere(*manifest,&to_delete); query_contents.NotHere(*manifest,&to_delete);
} else { } else {
uids_on_disk->NotHere(*manifest,&to_delete); uids_on_disk->NotHere(*manifest,&to_delete);
delete uids_on_disk; delete uids_on_disk;
uids_on_disk = NULL; uids_on_disk = NULL;
} }
for (int32 i = 0; i < to_delete.CountItems(); i++) for (int32 i = 0; i < to_delete.CountItems(); i++)
DeleteMessage(to_delete[i]); DeleteMessage(to_delete[i]);
//*(unique_ids) -= to_delete; --- This line causes bad things to //*(unique_ids) -= to_delete; --- This line causes bad things to
// happen (POP3 client uses the wrong indices to retrieve // happen (POP3 client uses the wrong indices to retrieve
// messages). Without it, bad things don't happen. // messages). Without it, bad things don't happen.