xref: /haiku/src/add-ons/tracker/mark_as/MarkAs.cpp (revision a3e794ae459fec76826407f8ba8c94cd3535f128)
1 /*
2  * Copyright 2009-2013, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <new>
8 
9 #include <Directory.h>
10 #include <E-mail.h>
11 #include <Entry.h>
12 #include <FindDirectory.h>
13 #include <InterfaceDefs.h>
14 #include <MailDaemon.h>
15 #include <mail_util.h>
16 #include <MenuItem.h>
17 #include <Message.h>
18 #include <Node.h>
19 #include <Path.h>
20 #include <PopUpMenu.h>
21 #include <String.h>
22 
23 
24 static BPoint
25 mouse_position()
26 {
27 	// Returns the mouse position in screen coordinates
28 	BPoint position;
29 	get_mouse(&position, NULL);
30 	return position;
31 }
32 
33 
34 static void
35 add_status_item(BMenu* menu, const char* name)
36 {
37 	if (menu->FindItem(name) != NULL)
38 		return;
39 
40 	// Sort items alphabetically
41 	int32 index;
42 	for (index = 0; index < menu->CountItems(); index++) {
43 		if (strcmp(menu->ItemAt(index)->Label(), name) > 0)
44 			break;
45 	}
46 
47 	menu->AddItem(new BMenuItem(name, NULL), index);
48 }
49 
50 
51 static void
52 retrieve_status_items(BMenu* menu)
53 {
54 	BPath path;
55 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
56 		return;
57 
58 	path.Append("Mail/status");
59 
60 	BDirectory directory(path.Path());
61 
62 	entry_ref ref;
63 	while (directory.GetNextRef(&ref) == B_OK) {
64 		if (!strcmp(ref.name, ".") || !strcmp(ref.name, ".."))
65 			continue;
66 
67 		add_status_item(menu, ref.name);
68 	}
69 
70 	add_status_item(menu, "New");
71 	add_status_item(menu, "Read");
72 	add_status_item(menu, "Replied");
73 }
74 
75 
76 // #pragma mark -
77 
78 
79 extern "C" void
80 process_refs(entry_ref dir, BMessage* message, void* /*reserved*/)
81 {
82 	BPopUpMenu* menu = new BPopUpMenu("status");
83 	retrieve_status_items(menu);
84 
85 	BMenuItem* item = menu->Go(mouse_position() - BPoint(5, 5), false, true);
86 	if (item == NULL)
87 		return;
88 
89 	BString status = item->Label();
90 	//TODO:This won't work anymore when the menu gets translated! Use index!
91 
92 	entry_ref ref;
93 	for (int i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) {
94 		BNode node(&ref);
95 		BString type;
96 
97 		if (node.InitCheck() == B_OK
98 			&& node.ReadAttrString("BEOS:TYPE", &type) == B_OK
99 			&& (type == B_MAIL_TYPE || type == B_PARTIAL_MAIL_TYPE)) {
100 			BString previousStatus;
101 			read_flags previousRead;
102 
103 			// Update the MAIL:read flag
104 			if (status == "New") {
105 				if (read_read_attr(node, previousRead) != B_OK ||
106 					previousRead != B_UNREAD)
107 					write_read_attr(node, B_UNREAD);
108 			}
109 			else if (status == "Read") {
110 				// if we're marking it via the add-on, we haven't really read it
111 				// so use B_SEEN instead of B_READ
112 				// Check both B_SEEN and B_READ
113 				// (so we don't overwrite B_READ with B_SEEN)
114 				if (read_read_attr(node, previousRead) != B_OK ||
115 					(previousRead != B_SEEN && previousRead != B_READ)) {
116 					int32 account;
117 					if (node.ReadAttr(B_MAIL_ATTR_ACCOUNT_ID, B_INT32_TYPE,
118 							0LL, &account, sizeof(account)) == sizeof(account))
119 						BMailDaemon().MarkAsRead(account, ref, B_SEEN);
120 					else
121 						write_read_attr(node, B_SEEN);
122 				}
123 			}
124 			// ignore "Replied"; no matching MAIL:read status
125 
126 			// We want to keep the previous behavior of updating the status
127 			// string, but write_read_attr will only change the status string
128 			// if it's one of "New", "Seen", or "Read" (and not, for example,
129 			// "Replied"), so we change the status string here
130 			// Only update the attribute if there is an actual change
131 			if (node.ReadAttrString(B_MAIL_ATTR_STATUS, &previousStatus) != B_OK
132 				|| previousStatus != status)
133 				node.WriteAttrString(B_MAIL_ATTR_STATUS, &status);
134 		}
135 	}
136 }
137 
138