diff --git a/data/artwork/icons/File_Mail_label b/data/artwork/icons/File_Mail_label new file mode 100644 index 0000000000..360458e511 Binary files /dev/null and b/data/artwork/icons/File_Mail_label differ diff --git a/src/add-ons/tracker/Jamfile b/src/add-ons/tracker/Jamfile index 48dc39d6f4..0a7dbeb65f 100644 --- a/src/add-ons/tracker/Jamfile +++ b/src/add-ons/tracker/Jamfile @@ -2,6 +2,7 @@ SubDir HAIKU_TOP src add-ons tracker ; SubInclude HAIKU_TOP src add-ons tracker filetype ; SubInclude HAIKU_TOP src add-ons tracker iconvader ; +SubInclude HAIKU_TOP src add-ons tracker label_as ; SubInclude HAIKU_TOP src add-ons tracker opentargetfolder ; SubInclude HAIKU_TOP src add-ons tracker mark_as ; SubInclude HAIKU_TOP src add-ons tracker openterminal ; diff --git a/src/add-ons/tracker/label_as/Jamfile b/src/add-ons/tracker/label_as/Jamfile new file mode 100644 index 0000000000..91cce5e408 --- /dev/null +++ b/src/add-ons/tracker/label_as/Jamfile @@ -0,0 +1,16 @@ +SubDir HAIKU_TOP src add-ons tracker label_as ; + +UsePrivateHeaders mail ; + +AddResources Label\ as… : LabelAs.rdef ; + +Addon Label\ as… : + LabelAs.cpp + : be tracker [ TargetLibsupc++ ] localestub +; + +DoCatalogs Label\ as… : + x-vnd.Haiku-LabelAs + : + LabelAs.cpp +; diff --git a/src/add-ons/tracker/label_as/LabelAs.cpp b/src/add-ons/tracker/label_as/LabelAs.cpp new file mode 100644 index 0000000000..f57bd3e108 --- /dev/null +++ b/src/add-ons/tracker/label_as/LabelAs.cpp @@ -0,0 +1,132 @@ +/* + * Copyright 2026 Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "Label-as add-on" + + +BCollator collator; + + +static int +compare_menu_items(const BMenuItem* a, const BMenuItem* b) +{ + return collator.Compare(a->Label(), b->Label()); +} + + +static BPoint +mouse_position() +{ + BPoint position; + get_mouse(&position, NULL); + return position; +} + + +void +open_labels_folder() +{ + BPath path; + find_directory(B_USER_SETTINGS_DIRECTORY, &path); + path.Append("Mail/labels"); + + BEntry entry(path.Path()); + if (!entry.Exists()) + create_directory(path.Path(), 0777); + + BEntry folderEntry; + if (folderEntry.SetTo(path.Path()) == B_OK + && folderEntry.Exists()) { + BMessage openFolderCommand(B_REFS_RECEIVED); + BMessenger tracker("application/x-vnd.Be-TRAK"); + + entry_ref ref; + folderEntry.GetRef(&ref); + openFolderCommand.AddRef("refs", &ref); + tracker.SendMessage(&openFolderCommand); + } +} + + +static void +retrieve_label_items(BMenu* menu) +{ + menu->AddItem(new BMenuItem(B_TRANSLATE("Remove label"), NULL)); + menu->AddSeparatorItem(); + + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) + return; + + path.Append("Mail/labels"); + BDirectory directory(path.Path()); + BObjectList items; + entry_ref ref; + + while (directory.GetNextRef(&ref) == B_OK) + items.AddItem(new BMenuItem(ref.name, NULL)); + + if (!items.IsEmpty()) { + if (BLocale::Default()->GetCollator(&collator) == B_OK) { + collator.SetNumericSorting(true); + items.SortItems(compare_menu_items); + } + for (int32 i = 0; i < items.CountItems(); i++) + menu->AddItem(items.ItemAt(i)); + menu->AddSeparatorItem(); + } + menu->AddItem(new BMenuItem(B_TRANSLATE("Manage labels" B_UTF8_ELLIPSIS), NULL)); +} + + +// #pragma mark - + + +extern "C" void +process_refs(entry_ref dir, BMessage* message, void* /*reserved*/) +{ + BPopUpMenu* menu = new BPopUpMenu("labels"); + retrieve_label_items(menu); + + BMenuItem* item = menu->Go(mouse_position() - BPoint(5, 5), false, true); + if (item == NULL) + return; + + BString label = item->Label(); + entry_ref ref; + for (int i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) { + BNode node(&ref); + BString type; + BString previousLabel; + if (node.InitCheck() == B_OK && node.ReadAttrString("BEOS:TYPE", &type) == B_OK + && (type == B_MAIL_TYPE || type == B_PARTIAL_MAIL_TYPE)) { + if (label == B_TRANSLATE("Remove label")) + node.RemoveAttr(B_MAIL_ATTR_LABEL); + else if (label == B_TRANSLATE("Manage labels" B_UTF8_ELLIPSIS)) + open_labels_folder(); + else if (node.ReadAttrString(B_MAIL_ATTR_LABEL, &previousLabel) != B_OK + || previousLabel != label) + node.WriteAttrString(B_MAIL_ATTR_LABEL, &label); + } + } +} diff --git a/src/add-ons/tracker/label_as/LabelAs.rdef b/src/add-ons/tracker/label_as/LabelAs.rdef new file mode 100644 index 0000000000..0c6fa7d683 --- /dev/null +++ b/src/add-ons/tracker/label_as/LabelAs.rdef @@ -0,0 +1,34 @@ +resource app_signature "application/x-vnd.Haiku-LabelAs"; + +resource file_types message { + "types" = "text/x-email", + "types" = "text/x-partial-email" +}; + +resource app_version { + major = 1, + middle = 0, + minor = 0, + + /* 0 = development 1 = alpha 2 = beta + 3 = gamma 4 = golden master 5 = final */ + variety = 0, + + internal = 1, + + short_info = "LabelAs, Copyright 2026 Haiku, Inc.", + long_info = "A Tracker Add-on that marks emails with the chosen label." +}; + +resource vector_icon { + $"6E636966060500040167020006023A94CE3C078BBE370C3CD1394B9EF94A1372" + $"00FAF9D2FFDDDB8F03FF0000020006023AC26B3A272ABB621E3C2B0B4A03F64A" + $"005700010101FF807E5D020006033959AFBA52CE3AE8E03A190A49C920491610" + $"2F67CBFFA80594DDFD1BAFFB070A04495D4C5E604A5C480A04363A5C49485D22" + $"4A0A044F464A4B504E55490802384244480802BB11C23D3E4B0802B946C3AF3E" + $"510606AE0B383D4434BFC9BB81C22FBAAD46314D33C41EBBC74D354936404008" + $"0A010100000A0001011001178402040A020101000A030102000A040303040510" + $"01178100040A00010630242201178300040A0501062024220A00001001178200" + $"04" +}; + diff --git a/src/add-ons/tracker/mark_as/MarkAs.cpp b/src/add-ons/tracker/mark_as/MarkAs.cpp index b7ea6304da..1c035fce85 100644 --- a/src/add-ons/tracker/mark_as/MarkAs.cpp +++ b/src/add-ons/tracker/mark_as/MarkAs.cpp @@ -48,31 +48,6 @@ add_status_item(BMenu* menu, const char* name) } -static void -retrieve_status_items(BMenu* menu) -{ - BPath path; - if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) - return; - - path.Append("Mail/status"); - - BDirectory directory(path.Path()); - - entry_ref ref; - while (directory.GetNextRef(&ref) == B_OK) { - if (!strcmp(ref.name, ".") || !strcmp(ref.name, "..")) - continue; - - add_status_item(menu, ref.name); - } - - add_status_item(menu, "New"); - add_status_item(menu, "Read"); - add_status_item(menu, "Replied"); -} - - // #pragma mark - @@ -80,7 +55,9 @@ extern "C" void process_refs(entry_ref dir, BMessage* message, void* /*reserved*/) { BPopUpMenu* menu = new BPopUpMenu("status"); - retrieve_status_items(menu); + add_status_item(menu, "New"); + add_status_item(menu, "Read"); + add_status_item(menu, "Replied"); BMenuItem* item = menu->Go(mouse_position() - BPoint(5, 5), false, true); if (item == NULL)