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