1141674aaSRyan Leavengood/*
2cf14e7f2SAxel Dörfler * Copyright 2009-2013, Axel D��rfler, axeld@pinc-software.de.
3141674aaSRyan Leavengood * Distributed under the terms of the MIT License.
4141674aaSRyan Leavengood */
5141674aaSRyan Leavengood
6141674aaSRyan Leavengood
77843ca4cSAxel Dörfler#include <new>
87843ca4cSAxel Dörfler
966570f5dSAxel Dörfler#include <Directory.h>
10ee5f0dacSFrançois Revol#include <E-mail.h>
11141674aaSRyan Leavengood#include <Entry.h>
1266570f5dSAxel Dörfler#include <FindDirectory.h>
1319ec74b0SStephan Aßmus#include <InterfaceDefs.h>
14ee5f0dacSFrançois Revol#include <MailDaemon.h>
15ee5f0dacSFrançois Revol#include <mail_util.h>
1666570f5dSAxel Dörfler#include <MenuItem.h>
17141674aaSRyan Leavengood#include <Message.h>
18141674aaSRyan Leavengood#include <Node.h>
1966570f5dSAxel Dörfler#include <Path.h>
2066570f5dSAxel Dörfler#include <PopUpMenu.h>
21141674aaSRyan Leavengood#include <String.h>
22141674aaSRyan Leavengood
23141674aaSRyan Leavengood
2466570f5dSAxel Dörflerstatic BPoint
2566570f5dSAxel Dörflermouse_position()
2666570f5dSAxel Dörfler{
2719ec74b0SStephan Aßmus	// Returns the mouse position in screen coordinates
2866570f5dSAxel Dörfler	BPoint position;
2919ec74b0SStephan Aßmus	get_mouse(&position, NULL);
3066570f5dSAxel Dörfler	return position;
3166570f5dSAxel Dörfler}
3266570f5dSAxel Dörfler
3366570f5dSAxel Dörfler
3466570f5dSAxel Dörflerstatic void
3566570f5dSAxel Dörfleradd_status_item(BMenu* menu, const char* name)
36141674aaSRyan Leavengood{
3766570f5dSAxel Dörfler	if (menu->FindItem(name) != NULL)
3866570f5dSAxel Dörfler		return;
3966570f5dSAxel Dörfler
4066570f5dSAxel Dörfler	// Sort items alphabetically
4166570f5dSAxel Dörfler	int32 index;
4266570f5dSAxel Dörfler	for (index = 0; index < menu->CountItems(); index++) {
4366570f5dSAxel Dörfler		if (strcmp(menu->ItemAt(index)->Label(), name) > 0)
4466570f5dSAxel Dörfler			break;
4566570f5dSAxel Dörfler	}
4666570f5dSAxel Dörfler
4766570f5dSAxel Dörfler	menu->AddItem(new BMenuItem(name, NULL), index);
4866570f5dSAxel Dörfler}
4966570f5dSAxel Dörfler
5066570f5dSAxel Dörfler
5166570f5dSAxel Dörflerstatic void
5266570f5dSAxel Dörflerretrieve_status_items(BMenu* menu)
5366570f5dSAxel Dörfler{
5466570f5dSAxel Dörfler	BPath path;
5566570f5dSAxel Dörfler	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
5666570f5dSAxel Dörfler		return;
5766570f5dSAxel Dörfler
5866570f5dSAxel Dörfler	path.Append("Mail/status");
5966570f5dSAxel Dörfler
6066570f5dSAxel Dörfler	BDirectory directory(path.Path());
6166570f5dSAxel Dörfler
6271c8e7e8SRyan Leavengood	entry_ref ref;
6366570f5dSAxel Dörfler	while (directory.GetNextRef(&ref) == B_OK) {
6466570f5dSAxel Dörfler		if (!strcmp(ref.name, ".") || !strcmp(ref.name, ".."))
6566570f5dSAxel Dörfler			continue;
6666570f5dSAxel Dörfler
6766570f5dSAxel Dörfler		add_status_item(menu, ref.name);
6866570f5dSAxel Dörfler	}
6966570f5dSAxel Dörfler
7066570f5dSAxel Dörfler	add_status_item(menu, "New");
7166570f5dSAxel Dörfler	add_status_item(menu, "Read");
7266570f5dSAxel Dörfler	add_status_item(menu, "Replied");
7366570f5dSAxel Dörfler}
74141674aaSRyan Leavengood
7566570f5dSAxel Dörfler
7666570f5dSAxel Dörfler// #pragma mark -
7766570f5dSAxel Dörfler
7866570f5dSAxel Dörfler
7966570f5dSAxel Dörflerextern "C" void
8066570f5dSAxel Dörflerprocess_refs(entry_ref dir, BMessage* message, void* /*reserved*/)
8166570f5dSAxel Dörfler{
8266570f5dSAxel Dörfler	BPopUpMenu* menu = new BPopUpMenu("status");
8366570f5dSAxel Dörfler	retrieve_status_items(menu);
8466570f5dSAxel Dörfler
8566570f5dSAxel Dörfler	BMenuItem* item = menu->Go(mouse_position() - BPoint(5, 5), false, true);
8666570f5dSAxel Dörfler	if (item == NULL)
8766570f5dSAxel Dörfler		return;
8866570f5dSAxel Dörfler
8966570f5dSAxel Dörfler	BString status = item->Label();
90ee5f0dacSFrançois Revol	//TODO:This won't work anymore when the menu gets translated! Use index!
9166570f5dSAxel Dörfler
9266570f5dSAxel Dörfler	entry_ref ref;
9366570f5dSAxel Dörfler	for (int i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) {
9471c8e7e8SRyan Leavengood		BNode node(&ref);
9566570f5dSAxel Dörfler		BString type;
9666570f5dSAxel Dörfler
9766570f5dSAxel Dörfler		if (node.InitCheck() == B_OK
9866570f5dSAxel Dörfler			&& node.ReadAttrString("BEOS:TYPE", &type) == B_OK
99ee5f0dacSFrançois Revol			&& (type == B_MAIL_TYPE || type == B_PARTIAL_MAIL_TYPE)) {
10066570f5dSAxel Dörfler			BString previousStatus;
101ee5f0dacSFrançois Revol			read_flags previousRead;
102cf14e7f2SAxel Dörfler
103ee5f0dacSFrançois Revol			// Update the MAIL:read flag
104ee5f0dacSFrançois Revol			if (status == "New") {
105ee5f0dacSFrançois Revol				if (read_read_attr(node, previousRead) != B_OK ||
106ee5f0dacSFrançois Revol					previousRead != B_UNREAD)
107ee5f0dacSFrançois Revol					write_read_attr(node, B_UNREAD);
108ee5f0dacSFrançois Revol			}
109ee5f0dacSFrançois Revol			else if (status == "Read") {
110ee5f0dacSFrançois Revol				// if we're marking it via the add-on, we haven't really read it
111ee5f0dacSFrançois Revol				// so use B_SEEN instead of B_READ
112ee5f0dacSFrançois Revol				// Check both B_SEEN and B_READ
113ee5f0dacSFrançois Revol				// (so we don't overwrite B_READ with B_SEEN)
114ee5f0dacSFrançois Revol				if (read_read_attr(node, previousRead) != B_OK ||
115ee5f0dacSFrançois Revol					(previousRead != B_SEEN && previousRead != B_READ)) {
116ee5f0dacSFrançois Revol					int32 account;
117ee5f0dacSFrançois Revol					if (node.ReadAttr(B_MAIL_ATTR_ACCOUNT_ID, B_INT32_TYPE,
118cf14e7f2SAxel Dörfler							0LL, &account, sizeof(account)) == sizeof(account))
119cf14e7f2SAxel Dörfler						BMailDaemon().MarkAsRead(account, ref, B_SEEN);
120ee5f0dacSFrançois Revol					else
121ee5f0dacSFrançois Revol						write_read_attr(node, B_SEEN);
122ee5f0dacSFrançois Revol				}
123ee5f0dacSFrançois Revol			}
124ee5f0dacSFrançois Revol			// ignore "Replied"; no matching MAIL:read status
125ee5f0dacSFrançois Revol
126ee5f0dacSFrançois Revol			// We want to keep the previous behavior of updating the status
127ee5f0dacSFrançois Revol			// string, but write_read_attr will only change the status string
128ee5f0dacSFrançois Revol			// if it's one of "New", "Seen", or "Read" (and not, for example,
129ee5f0dacSFrançois Revol			// "Replied"), so we change the status string here
13066570f5dSAxel Dörfler			// Only update the attribute if there is an actual change
131ee5f0dacSFrançois Revol			if (node.ReadAttrString(B_MAIL_ATTR_STATUS, &previousStatus) != B_OK
13266570f5dSAxel Dörfler				|| previousStatus != status)
133ee5f0dacSFrançois Revol				node.WriteAttrString(B_MAIL_ATTR_STATUS, &status);
13466570f5dSAxel Dörfler		}
13571c8e7e8SRyan Leavengood	}
13666570f5dSAxel Dörfler}
137141674aaSRyan Leavengood
138