1 /* 2 * Copyright 2009, 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 <Entry.h> 11 #include <FindDirectory.h> 12 #include <MenuItem.h> 13 #include <Message.h> 14 #include <Node.h> 15 #include <Path.h> 16 #include <PopUpMenu.h> 17 #include <String.h> 18 #include <View.h> 19 #include <Window.h> 20 21 22 /*! Returns the current mouse position in screen coordinates. 23 Since there is no method to retrieve this in the Be API without a view, 24 this looks a bit more complicated. 25 */ 26 static BPoint 27 mouse_position() 28 { 29 BWindow* window = new BWindow(BRect(-1000, -1000, -900, -900), "mouse", 30 B_NO_BORDER_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 31 B_AVOID_FRONT | B_AVOID_FOCUS); 32 BView* view = new BView(window->Bounds(), "mouse", B_FOLLOW_ALL, 0); 33 window->AddChild(view); 34 window->Run(); 35 36 window->Lock(); 37 38 BPoint position; 39 uint32 buttons; 40 view->GetMouse(&position, &buttons); 41 view->ConvertToScreen(&position); 42 43 window->Quit(); 44 45 return position; 46 } 47 48 49 static void 50 add_status_item(BMenu* menu, const char* name) 51 { 52 if (menu->FindItem(name) != NULL) 53 return; 54 55 // Sort items alphabetically 56 int32 index; 57 for (index = 0; index < menu->CountItems(); index++) { 58 if (strcmp(menu->ItemAt(index)->Label(), name) > 0) 59 break; 60 } 61 62 menu->AddItem(new BMenuItem(name, NULL), index); 63 } 64 65 66 static void 67 retrieve_status_items(BMenu* menu) 68 { 69 BPath path; 70 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) 71 return; 72 73 path.Append("Mail/status"); 74 75 BDirectory directory(path.Path()); 76 77 entry_ref ref; 78 while (directory.GetNextRef(&ref) == B_OK) { 79 if (!strcmp(ref.name, ".") || !strcmp(ref.name, "..")) 80 continue; 81 82 add_status_item(menu, ref.name); 83 } 84 85 add_status_item(menu, "New"); 86 add_status_item(menu, "Read"); 87 add_status_item(menu, "Replied"); 88 } 89 90 91 // #pragma mark - 92 93 94 extern "C" void 95 process_refs(entry_ref dir, BMessage* message, void* /*reserved*/) 96 { 97 BPopUpMenu* menu = new BPopUpMenu("status"); 98 retrieve_status_items(menu); 99 100 BMenuItem* item = menu->Go(mouse_position() - BPoint(5, 5), false, true); 101 if (item == NULL) 102 return; 103 104 BString status = item->Label(); 105 106 entry_ref ref; 107 for (int i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) { 108 BNode node(&ref); 109 BString type; 110 111 if (node.InitCheck() == B_OK 112 && node.ReadAttrString("BEOS:TYPE", &type) == B_OK 113 && type == "text/x-email") { 114 BString previousStatus; 115 116 // Only update the attribute if there is an actual change 117 if (node.ReadAttrString("MAIL:status", &previousStatus) != B_OK 118 || previousStatus != status) 119 node.WriteAttrString("MAIL:status", &status); 120 } 121 } 122 } 123 124