2 * Copyright 2004-2012, Haiku Inc. All Rights Reserved.
3 * Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
5 * Distributed under the terms of the MIT License.
9 //! mail_daemon's deskbar menu and view
12 #include "DeskbarView.h"
20 #include <Directory.h>
22 #include <FindDirectory.h>
23 #include <IconUtils.h>
24 #include <kernel/fs_info.h>
25 #include <kernel/fs_index.h>
27 #include <MessageFormat.h>
28 #include <Messenger.h>
30 #include <NodeMonitor.h>
31 #include <OpenWithTracker.h>
33 #include <PopUpMenu.h>
36 #include <Resources.h>
40 #include <VolumeRoster.h>
44 #include <MailDaemon.h>
45 #include <MailSettings.h>
47 #include <MailPrivate.h>
49 #include "DeskbarViewIcons.h"
52 #undef B_TRANSLATION_CONTEXT
53 #define B_TRANSLATION_CONTEXT "DeskbarView"
56 const char* kTrackerSignature
= "application/x-vnd.Be-TRAK";
59 //-----The following #defines get around a bug in get_image_info on ppc---
61 #define text_part text
62 #define text_part_size text_size
64 #define text_part data
65 #define text_part_size data_size
68 extern "C" _EXPORT BView
* instantiate_deskbar_item();
71 status_t
our_image(image_info
* image
)
75 while ((ret
= get_next_image_info(0,&cookie
,image
)) == B_OK
)
77 if ((char*)our_image
>= (char*)image
->text_part
&&
78 (char*)our_image
<= (char*)image
->text_part
+ image
->text_part_size
)
85 BView
* instantiate_deskbar_item(void)
87 return new DeskbarView(BRect(0, 0, 15, 15));
91 //-------------------------------------------------------------------------------
95 DeskbarView::DeskbarView(BRect frame
)
97 BView(frame
, "mail_daemon", B_FOLLOW_NONE
, B_WILL_DRAW
| B_PULSE_NEEDED
),
98 fStatus(kStatusNoMail
),
105 DeskbarView::DeskbarView(BMessage
*message
)
108 fStatus(kStatusNoMail
),
115 DeskbarView::~DeskbarView()
117 for (int i
= 0; i
< kStatusCount
; i
++)
120 for (int32 i
= 0; i
< fNewMailQueries
.CountItems(); i
++)
121 delete ((BQuery
*)(fNewMailQueries
.ItemAt(i
)));
125 void DeskbarView::AttachedToWindow()
127 BView::AttachedToWindow();
130 if (ViewUIColor() == B_NO_COLOR
)
131 SetLowColor(ViewColor());
133 SetLowUIColor(ViewUIColor());
135 if (be_roster
->IsRunning(B_MAIL_DAEMON_SIGNATURE
)) {
139 deskbar
.RemoveItem("mail_daemon");
144 bool DeskbarView::_EntryInTrash(const entry_ref
* ref
)
147 BVolume
volume(ref
->device
);
149 if (volume
.InitCheck() != B_OK
150 || find_directory(B_TRASH_DIRECTORY
, &path
, false, &volume
) != B_OK
)
153 BDirectory
trash(path
.Path());
154 return trash
.Contains(&entry
);
158 void DeskbarView::_RefreshMailQuery()
160 for (int32 i
= 0; i
< fNewMailQueries
.CountItems(); i
++)
161 delete ((BQuery
*)(fNewMailQueries
.ItemAt(i
)));
162 fNewMailQueries
.MakeEmpty();
164 BVolumeRoster volumes
;
168 while (volumes
.GetNextVolume(&volume
) == B_OK
) {
169 BQuery
*newMailQuery
= new BQuery
;
170 newMailQuery
->SetTarget(this);
171 newMailQuery
->SetVolume(&volume
);
172 newMailQuery
->PushAttr(B_MAIL_ATTR_READ
);
173 newMailQuery
->PushInt32(B_UNREAD
);
174 newMailQuery
->PushOp(B_EQ
);
175 newMailQuery
->PushAttr("BEOS:TYPE");
176 newMailQuery
->PushString("text/x-email");
177 newMailQuery
->PushOp(B_EQ
);
178 newMailQuery
->PushAttr("BEOS:TYPE");
179 newMailQuery
->PushString("text/x-partial-email");
180 newMailQuery
->PushOp(B_EQ
);
181 newMailQuery
->PushOp(B_OR
);
182 newMailQuery
->PushOp(B_AND
);
183 newMailQuery
->Fetch();
186 while (newMailQuery
->GetNextEntry(&entry
) == B_OK
) {
187 if (entry
.InitCheck() == B_OK
) {
190 if (!_EntryInTrash(&ref
))
195 fNewMailQueries
.AddItem(newMailQuery
);
198 fStatus
= (fNewMessages
> 0) ? kStatusNewMail
: kStatusNoMail
;
203 DeskbarView
* DeskbarView::Instantiate(BMessage
*data
)
205 if (!validate_instantiation(data
, "DeskbarView"))
208 return new DeskbarView(data
);
212 status_t
DeskbarView::Archive(BMessage
*data
,bool deep
) const
214 BView::Archive(data
, deep
);
216 data
->AddString("add_on", B_MAIL_DAEMON_SIGNATURE
);
222 DeskbarView::Draw(BRect
/*updateRect*/)
224 if (fBitmaps
[fStatus
] == NULL
)
227 SetDrawingMode(B_OP_ALPHA
);
228 DrawBitmap(fBitmaps
[fStatus
]);
229 SetDrawingMode(B_OP_COPY
);
234 DeskbarView::MessageReceived(BMessage
* message
)
236 switch (message
->what
) {
237 case MD_CHECK_SEND_NOW
:
238 // also happens in DeskbarView::MouseUp() with
239 // B_TERTIARY_MOUSE_BUTTON pressed
240 BMailDaemon().CheckAndSendQueuedMail();
242 case MD_CHECK_FOR_MAILS
:
243 BMailDaemon().CheckMail(message
->FindInt32("account"));
246 BMailDaemon().SendQueuedMail();
251 char* argv
[] = {(char *)"New Message", (char *)"mailto:"};
252 be_roster
->Launch("text/x-email", 2, argv
);
256 be_roster
->Launch("application/x-vnd.Haiku-Mail");
259 case MD_REFRESH_QUERY
:
270 message
->FindInt32("opcode", &what
);
271 message
->FindInt32("device", &device
);
272 message
->FindInt64("directory", &directory
);
274 case B_ENTRY_CREATED
:
275 if (message
->FindString("name", &name
) == B_OK
) {
277 ref
.directory
= directory
;
279 if (!_EntryInTrash(&ref
))
283 case B_ENTRY_REMOVED
:
285 node
.device
= device
;
286 node
.node
= directory
;
287 BDirectory
dir(&node
);
288 BEntry
entry(&dir
, NULL
);
290 if (!_EntryInTrash(&ref
))
294 fStatus
= fNewMessages
> 0 ? kStatusNewMail
: kStatusNoMail
;
298 case B_QUIT_REQUESTED
:
299 BMailDaemon().Quit();
302 // open received files in the standard mail application
303 case B_REFS_RECEIVED
:
305 BMessage
argv(B_ARGV_RECEIVED
);
306 argv
.AddString("argv", "E-mail");
312 while (message
->FindRef("refs", i
++, &ref
) == B_OK
313 && path
.SetTo(&ref
) == B_OK
) {
314 //fprintf(stderr,"got %s\n", path.Path());
315 argv
.AddString("argv", path
.Path());
319 argv
.AddInt32("argc", i
);
320 be_roster
->Launch("text/x-email", &argv
);
325 BView::MessageReceived(message
);
331 DeskbarView::_InitBitmaps()
333 for (int i
= 0; i
< kStatusCount
; i
++)
337 if (our_image(&info
) != B_OK
)
340 BFile
file(info
.name
, B_READ_ONLY
);
341 if (file
.InitCheck() != B_OK
)
344 BResources
resources(&file
);
345 if (resources
.InitCheck() != B_OK
)
348 for (int i
= 0; i
< kStatusCount
; i
++) {
349 const void* data
= NULL
;
351 data
= resources
.LoadResource(B_VECTOR_ICON_TYPE
,
352 kIconNoMail
+ i
, &size
);
354 BBitmap
* icon
= new BBitmap(Bounds(), B_RGBA32
);
355 if (icon
->InitCheck() == B_OK
356 && BIconUtils::GetVectorIcon((const uint8
*)data
,
357 size
, icon
) == B_OK
) {
369 // TODO: Check if mail_daemon is still running
374 DeskbarView::MouseUp(BPoint pos
)
376 if ((fLastButtons
& B_PRIMARY_MOUSE_BUTTON
) !=0
377 && OpenWithTracker(B_USER_SETTINGS_DIRECTORY
, "Mail/mailbox") != B_OK
) {
379 _GetNewQueryRef(ref
);
381 BMessenger
trackerMessenger(kTrackerSignature
);
382 BMessage
message(B_REFS_RECEIVED
);
383 message
.AddRef("refs", &ref
);
385 trackerMessenger
.SendMessage(&message
);
388 if ((fLastButtons
& B_TERTIARY_MOUSE_BUTTON
) != 0)
389 BMailDaemon().CheckMail();
394 DeskbarView::MouseDown(BPoint pos
)
396 Looper()->CurrentMessage()->FindInt32("buttons", &fLastButtons
);
398 if ((fLastButtons
& B_SECONDARY_MOUSE_BUTTON
) != 0) {
399 ConvertToScreen(&pos
);
401 BPopUpMenu
* menu
= _BuildMenu();
402 menu
->Go(pos
, true, true, BRect(pos
.x
- 2, pos
.y
- 2,
403 pos
.x
+ 2, pos
.y
+ 2), true);
409 DeskbarView::_CreateMenuLinks(BDirectory
& directory
, BPath
& path
)
411 status_t status
= directory
.SetTo(path
.Path());
415 // Check if the directory has to be created (and do it in this case,
416 // filling it with some standard links). Normally the installer will
417 // create the directory and fill it with links, so normally this doesn't
420 BEntry
entry(path
.Path());
421 if (status
!= B_ENTRY_NOT_FOUND
422 || entry
.GetParent(&directory
) < B_OK
423 || directory
.CreateDirectory(path
.Leaf(), NULL
) < B_OK
424 || directory
.SetTo(path
.Path()) < B_OK
)
428 find_directory(B_USER_DIRECTORY
, &targetPath
);
429 targetPath
.Append("mail/in");
431 directory
.CreateSymLink("Open Inbox Folder", targetPath
.Path(), NULL
);
432 targetPath
.GetParent(&targetPath
);
433 directory
.CreateSymLink("Open Mail Folder", targetPath
.Path(), NULL
);
435 // create the draft query
438 if (directory
.CreateFile("Open Draft", &file
) < B_OK
)
441 BString
string("MAIL:draft==1");
442 file
.WriteAttrString("_trk/qrystr", &string
);
444 file
.WriteAttrString("_trk/qryinitmime", &string
);
445 BNodeInfo(&file
).SetType("application/x-vnd.Be-query");
452 DeskbarView::_CreateNewMailQuery(BEntry
& query
)
454 BFile
file(&query
, B_READ_WRITE
| B_CREATE_FILE
);
455 if (file
.InitCheck() != B_OK
)
458 BString
string("((" B_MAIL_ATTR_READ
"<2)&&((BEOS:TYPE=="
459 "\"text/x-email\")||(BEOS:TYPE==\"text/x-partial-email\")))");
460 file
.WriteAttrString("_trk/qrystr", &string
);
461 file
.WriteAttrString("_trk/qryinitstr", &string
);
463 file
.WriteAttr("_trk/qryinitmode", B_INT32_TYPE
, 0, &mode
, sizeof(int32
));
465 file
.WriteAttrString("_trk/qryinitmime", &string
);
466 BNodeInfo(&file
).SetType("application/x-vnd.Be-query");
471 DeskbarView::_BuildMenu()
473 BPopUpMenu
* menu
= new BPopUpMenu(B_EMPTY_STRING
, false, false);
474 menu
->SetFont(be_plain_font
);
476 menu
->AddItem(new BMenuItem(B_TRANSLATE("Create new message"
477 B_UTF8_ELLIPSIS
), new BMessage(MD_OPEN_NEW
)));
478 menu
->AddSeparatorItem();
480 BMessenger
tracker(kTrackerSignature
);
487 find_directory(B_USER_SETTINGS_DIRECTORY
, &path
);
488 path
.Append("Mail/Menu Links");
490 BDirectory directory
;
491 if (_CreateMenuLinks(directory
, path
)) {
494 while (directory
.GetNextRef(&ref
) == B_OK
) {
498 // the true here dereferences the symlinks all the way :)
499 BEntry
entry(&ref
, true);
501 // do we want to use the NavMenu, or just an ordinary BMenuItem?
502 // we are using the NavMenu only for directories and queries
503 bool useNavMenu
= false;
505 if (entry
.InitCheck() == B_OK
) {
506 if (entry
.IsDirectory())
508 else if (entry
.IsFile()) {
509 // Files should use the BMenuItem unless they are queries
510 char mimeString
[B_MIME_TYPE_LENGTH
];
512 BNodeInfo
info(&node
);
513 if (info
.GetType(mimeString
) == B_OK
514 && strcmp(mimeString
, "application/x-vnd.Be-query")
518 // clobber the existing ref only if the symlink derefernces
519 // completely, otherwise we'll stick with what we have
523 msg
= new BMessage(B_REFS_RECEIVED
);
524 msg
->AddRef("refs", &ref
);
527 item
= new BMenuItem(navMenu
= new BNavMenu(path
.Leaf(),
528 B_REFS_RECEIVED
, tracker
), msg
);
529 navMenu
->SetNavDir(&ref
);
531 item
= new BMenuItem(path
.Leaf(), msg
);
534 if (entry
.InitCheck() != B_OK
)
535 item
->SetEnabled(false);
538 menu
->AddSeparatorItem();
541 // Hack for R5's buggy Query Notification
542 #ifdef HAIKU_TARGET_PLATFORM_BEOS
543 menu
->AddItem(new BMenuItem(B_TRANSLATE("Refresh New Mail Count"),
544 new BMessage(MD_REFRESH_QUERY
)));
547 // The New E-mail query
549 if (fNewMessages
> 0) {
550 static BMessageFormat
format(B_TRANSLATE(
551 "{0, plural, one{# new message} other{# new messages}}"));
553 format
.Format(string
, fNewMessages
);
555 _GetNewQueryRef(ref
);
557 item
= new BMenuItem(navMenu
= new BNavMenu(string
.String(),
558 B_REFS_RECEIVED
, BMessenger(kTrackerSignature
)),
559 msg
= new BMessage(B_REFS_RECEIVED
));
560 msg
->AddRef("refs", &ref
);
561 navMenu
->SetNavDir(&ref
);
565 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("No new messages"),
567 item
->SetEnabled(false);
570 BMailAccounts accounts
;
571 if ((modifiers() & B_SHIFT_KEY
) != 0) {
572 BMenu
*accountMenu
= new BMenu(B_TRANSLATE("Check for mails only"));
574 menu
->GetFont(&font
);
575 accountMenu
->SetFont(&font
);
577 for (int32 i
= 0; i
< accounts
.CountAccounts(); i
++) {
578 BMailAccountSettings
* account
= accounts
.AccountAt(i
);
580 BMessage
* message
= new BMessage(MD_CHECK_FOR_MAILS
);
581 message
->AddInt32("account", account
->AccountID());
583 accountMenu
->AddItem(new BMenuItem(account
->Name(), message
));
585 if (accounts
.CountAccounts() == 0) {
586 item
= new BMenuItem(B_TRANSLATE("<no accounts>"), NULL
);
587 item
->SetEnabled(false);
588 accountMenu
->AddItem(item
);
590 accountMenu
->SetTargetForItems(this);
591 menu
->AddItem(new BMenuItem(accountMenu
,
592 new BMessage(MD_CHECK_FOR_MAILS
)));
595 // menu->AddItem(new BMenuItem(B_TRANSLATE("Check For Mails Only"),
596 // new BMessage(MD_CHECK_FOR_MAILS)));
597 menu
->AddItem(new BMenuItem(B_TRANSLATE("Send pending mails"),
598 new BMessage(MD_SEND_MAILS
)));
600 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Check for mail now"),
601 new BMessage(MD_CHECK_SEND_NOW
)));
602 if (accounts
.CountAccounts() == 0)
603 item
->SetEnabled(false);
606 menu
->AddSeparatorItem();
607 menu
->AddItem(new BMenuItem(B_TRANSLATE("Settings" B_UTF8_ELLIPSIS
),
608 new BMessage(MD_OPEN_PREFS
)));
610 if (modifiers() & B_SHIFT_KEY
) {
611 menu
->AddItem(new BMenuItem(B_TRANSLATE("Shutdown mail services"),
612 new BMessage(B_QUIT_REQUESTED
)));
615 // Reset Item Targets (only those which aren't already set)
617 for (int32 i
= menu
->CountItems(); i
-- > 0;) {
618 item
= menu
->ItemAt(i
);
619 if (item
!= NULL
&& (msg
= item
->Message()) != NULL
) {
620 if (msg
->what
== B_REFS_RECEIVED
)
621 item
->SetTarget(tracker
);
623 item
->SetTarget(this);
631 DeskbarView::_GetNewQueryRef(entry_ref
& ref
)
634 find_directory(B_USER_SETTINGS_DIRECTORY
, &path
);
635 path
.Append("Mail/New E-mail");
636 BEntry
query(path
.Path());
638 _CreateNewMailQuery(query
);
639 return query
.GetRef(&ref
);