vfs: check userland buffers before reading them.
[haiku.git] / src / servers / mail / MailDaemonApplication.cpp
blob0a9c486e6c6f7f87b70b650af49d200ca16832bb
1 /*
2 * Copyright 2007-2016, Haiku, Inc. All rights reserved.
3 * Copyright 2001-2002 Dr. Zoidberg Enterprises. All rights reserved.
4 * Copyright 2011, Clemens Zeidler <haiku@clemens-zeidler.de>
5 * Distributed under the terms of the MIT License.
6 */
9 #include "MailDaemonApplication.h"
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <vector>
15 #include <Beep.h>
16 #include <Catalog.h>
17 #include <Deskbar.h>
18 #include <Directory.h>
19 #include <Entry.h>
20 #include <FindDirectory.h>
21 #include <fs_index.h>
22 #include <IconUtils.h>
23 #include <MessageFormat.h>
24 #include <NodeMonitor.h>
25 #include <Notification.h>
26 #include <Path.h>
27 #include <Roster.h>
28 #include <StringList.h>
29 #include <VolumeRoster.h>
31 #include <E-mail.h>
32 #include <MailDaemon.h>
33 #include <MailMessage.h>
34 #include <MailSettings.h>
36 #include <MailPrivate.h>
39 #undef B_TRANSLATION_CONTEXT
40 #define B_TRANSLATION_CONTEXT "MailDaemon"
43 static const uint32 kMsgStartAutoCheck = 'stAC';
44 static const uint32 kMsgAutoCheck = 'moto';
46 static const bigtime_t kStartAutoCheckDelay = 30000000;
47 // Wait 30 seconds before the first auto check - this usually lets the
48 // boot process settle down, and give the network a chance to come up.
51 struct send_mails_info {
52 send_mails_info()
54 bytes = 0;
57 BMessage files;
58 off_t bytes;
62 class InboundMessenger : public BMessenger {
63 public:
64 InboundMessenger(BInboundMailProtocol* protocol)
66 BMessenger(protocol)
70 status_t MarkAsRead(const entry_ref& ref, read_flags flag)
72 BMessage message(kMsgMarkMessageAsRead);
73 message.AddRef("ref", &ref);
74 message.AddInt32("read", flag);
76 return SendMessage(&message);
79 status_t SynchronizeMessages()
81 BMessage message(kMsgSyncMessages);
82 return SendMessage(&message);
87 // #pragma mark -
90 static void
91 makeIndices()
93 const char* stringIndices[] = {
94 B_MAIL_ATTR_CC, B_MAIL_ATTR_FROM, B_MAIL_ATTR_NAME,
95 B_MAIL_ATTR_PRIORITY, B_MAIL_ATTR_REPLY, B_MAIL_ATTR_STATUS,
96 B_MAIL_ATTR_SUBJECT, B_MAIL_ATTR_TO, B_MAIL_ATTR_THREAD,
97 B_MAIL_ATTR_ACCOUNT, NULL
100 // add mail indices for all devices capable of querying
102 int32 cookie = 0;
103 dev_t device;
104 while ((device = next_dev(&cookie)) >= B_OK) {
105 fs_info info;
106 if (fs_stat_dev(device, &info) < 0
107 || (info.flags & B_FS_HAS_QUERY) == 0)
108 continue;
110 for (int32 i = 0; stringIndices[i]; i++)
111 fs_create_index(device, stringIndices[i], B_STRING_TYPE, 0);
113 fs_create_index(device, "MAIL:draft", B_INT32_TYPE, 0);
114 fs_create_index(device, B_MAIL_ATTR_WHEN, B_INT32_TYPE, 0);
115 fs_create_index(device, B_MAIL_ATTR_FLAGS, B_INT32_TYPE, 0);
116 fs_create_index(device, B_MAIL_ATTR_ACCOUNT_ID, B_INT32_TYPE, 0);
117 fs_create_index(device, B_MAIL_ATTR_READ, B_INT32_TYPE, 0);
122 static void
123 addAttribute(BMessage& msg, const char* name, const char* publicName,
124 int32 type = B_STRING_TYPE, bool viewable = true, bool editable = false,
125 int32 width = 200)
127 msg.AddString("attr:name", name);
128 msg.AddString("attr:public_name", publicName);
129 msg.AddInt32("attr:type", type);
130 msg.AddBool("attr:viewable", viewable);
131 msg.AddBool("attr:editable", editable);
132 msg.AddInt32("attr:width", width);
133 msg.AddInt32("attr:alignment", B_ALIGN_LEFT);
137 // #pragma mark -
140 account_protocols::account_protocols()
142 inboundImage(-1),
143 inboundProtocol(NULL),
144 outboundImage(-1),
145 outboundProtocol(NULL)
150 // #pragma mark -
153 MailDaemonApplication::MailDaemonApplication()
155 BServer(B_MAIL_DAEMON_SIGNATURE, true, NULL),
156 fAutoCheckRunner(NULL)
158 fErrorLogWindow = new ErrorLogWindow(BRect(200, 200, 500, 250),
159 B_TRANSLATE("Mail daemon status log"), B_TITLED_WINDOW);
160 // install MimeTypes, attributes, indices, and the
161 // system beep add startup
162 MakeMimeTypes();
163 makeIndices();
164 add_system_beep_event("New E-mail");
168 MailDaemonApplication::~MailDaemonApplication()
170 delete fAutoCheckRunner;
172 for (int32 i = 0; i < fQueries.CountItems(); i++)
173 delete fQueries.ItemAt(i);
175 while (!fAccounts.empty()) {
176 _RemoveAccount(fAccounts.begin()->second);
177 fAccounts.erase(fAccounts.begin());
180 delete fLEDAnimation;
181 delete fNotification;
185 void
186 MailDaemonApplication::ReadyToRun()
188 InstallDeskbarIcon();
190 _InitAccounts();
192 // Start auto mail check with a delay
193 BMessage startAutoCheck(kMsgStartAutoCheck);
194 BMessageRunner::StartSending(this, &startAutoCheck,
195 kStartAutoCheckDelay, 1);
197 _InitNewMessagesCount();
199 fCentralBeep = false;
201 fNotification = new BNotification(B_INFORMATION_NOTIFICATION);
202 fNotification->SetGroup(B_TRANSLATE("Mail status"));
203 fNotification->SetMessageID("daemon_status");
204 _UpdateNewMessagesNotification();
206 app_info info;
207 be_roster->GetAppInfo(B_MAIL_DAEMON_SIGNATURE, &info);
208 BBitmap icon(BRect(0, 0, 32, 32), B_RGBA32);
209 BNode node(&info.ref);
210 BIconUtils::GetVectorIcon(&node, "BEOS:ICON", &icon);
211 fNotification->SetIcon(&icon);
213 fLEDAnimation = new LEDAnimation();
214 SetPulseRate(1000000);
218 void
219 MailDaemonApplication::RefsReceived(BMessage* message)
221 entry_ref ref;
222 for (int32 i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) {
223 BNode node(&ref);
224 if (node.InitCheck() != B_OK)
225 continue;
227 int32 account;
228 if (node.ReadAttr(B_MAIL_ATTR_ACCOUNT_ID, B_INT32_TYPE, 0, &account,
229 sizeof(account)) < 0)
230 continue;
232 BInboundMailProtocol* protocol = _InboundProtocol(account);
233 if (protocol == NULL)
234 continue;
236 BMessenger target;
237 BMessenger* replyTo = &target;
238 if (message->FindMessenger("target", &target) != B_OK)
239 replyTo = NULL;
241 protocol->FetchBody(ref, replyTo);
246 void
247 MailDaemonApplication::MessageReceived(BMessage* msg)
249 switch (msg->what) {
250 case kMsgStartAutoCheck:
251 _UpdateAutoCheckRunner();
252 break;
254 case kMsgAutoCheck:
255 // TODO: check whether internet is up and running!
256 // supposed to fall through
257 case kMsgCheckAndSend: // check & send messages
258 msg->what = kMsgSendMessages;
259 PostMessage(msg);
260 // supposed to fall trough
261 case kMsgCheckMessage: // check messages
262 GetNewMessages(msg);
263 break;
265 case kMsgSendMessages: // send messages
266 SendPendingMessages(msg);
267 break;
269 case kMsgSettingsUpdated:
270 fSettingsFile.Reload();
271 _UpdateAutoCheckRunner();
272 break;
274 case kMsgAccountsChanged:
275 _ReloadAccounts(msg);
276 break;
278 case kMsgMarkMessageAsRead:
280 int32 account = msg->FindInt32("account");
281 entry_ref ref;
282 if (msg->FindRef("ref", &ref) != B_OK)
283 break;
284 read_flags read = (read_flags)msg->FindInt32("read");
286 BInboundMailProtocol* protocol = _InboundProtocol(account);
287 if (protocol != NULL)
288 InboundMessenger(protocol).MarkAsRead(ref, read);
289 break;
292 case kMsgFetchBody:
293 RefsReceived(msg);
294 break;
296 case 'stwg': // Status window gone
298 BMessage reply('mnuc');
299 reply.AddInt32("num_new_messages", fNewMessages);
301 while ((msg = fFetchDoneRespondents.RemoveItemAt(0))) {
302 msg->SendReply(&reply);
303 delete msg;
306 if (fAlertString != B_EMPTY_STRING) {
307 fAlertString.Truncate(fAlertString.Length() - 1);
308 BAlert* alert = new BAlert(B_TRANSLATE("New Messages"),
309 fAlertString.String(), "OK", NULL, NULL, B_WIDTH_AS_USUAL);
310 alert->SetFeel(B_NORMAL_WINDOW_FEEL);
311 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
312 alert->Go(NULL);
313 fAlertString = B_EMPTY_STRING;
316 if (fCentralBeep) {
317 system_beep("New E-mail");
318 fCentralBeep = false;
320 break;
323 case 'mcbp':
324 if (fNewMessages > 0)
325 fCentralBeep = true;
326 break;
328 case kMsgCountNewMessages: // Number of new messages
330 BMessage reply('mnuc'); // Mail New message Count
331 if (msg->FindBool("wait_for_fetch_done")) {
332 fFetchDoneRespondents.AddItem(DetachCurrentMessage());
333 break;
336 reply.AddInt32("num_new_messages", fNewMessages);
337 msg->SendReply(&reply);
338 break;
341 case 'mblk': // Mail Blink
342 if (fNewMessages > 0)
343 fLEDAnimation->Start();
344 break;
346 case 'enda': // End Auto Check
347 delete fAutoCheckRunner;
348 fAutoCheckRunner = NULL;
349 break;
351 case 'numg':
353 static BMessageFormat format(B_TRANSLATE("{0, plural, "
354 "one{# new message} other{# new messages}} for %name\n"));
356 int32 numMessages = msg->FindInt32("num_messages");
357 fAlertString.Truncate(0);
358 format.Format(fAlertString, numMessages);
359 fAlertString.ReplaceFirst("%name", msg->FindString("name"));
360 break;
363 case B_QUERY_UPDATE:
365 int32 previousCount = fNewMessages;
367 int32 opcode = msg->GetInt32("opcode", -1);
368 switch (opcode) {
369 case B_ENTRY_CREATED:
370 fNewMessages++;
371 break;
372 case B_ENTRY_REMOVED:
373 fNewMessages--;
374 break;
375 default:
376 return;
379 _UpdateNewMessagesNotification();
381 if (fSettingsFile.ShowStatusWindow()
382 != B_MAIL_SHOW_STATUS_WINDOW_NEVER
383 && previousCount < fNewMessages) {
384 fNotification->Send();
386 break;
389 default:
390 BApplication::MessageReceived(msg);
391 break;
396 void
397 MailDaemonApplication::Pulse()
399 bigtime_t idle = idle_time();
400 if (fLEDAnimation->IsRunning() && idle < 100000)
401 fLEDAnimation->Stop();
405 bool
406 MailDaemonApplication::QuitRequested()
408 RemoveDeskbarIcon();
409 return true;
413 void
414 MailDaemonApplication::InstallDeskbarIcon()
416 BDeskbar deskbar;
418 if (!deskbar.HasItem("mail_daemon")) {
419 BRoster roster;
420 entry_ref ref;
422 status_t status = roster.FindApp(B_MAIL_DAEMON_SIGNATURE, &ref);
423 if (status < B_OK) {
424 fprintf(stderr, "Can't find application to tell deskbar: %s\n",
425 strerror(status));
426 return;
429 status = deskbar.AddItem(&ref);
430 if (status < B_OK) {
431 fprintf(stderr, "Can't add deskbar replicant: %s\n",
432 strerror(status));
433 return;
439 void
440 MailDaemonApplication::RemoveDeskbarIcon()
442 BDeskbar deskbar;
443 if (deskbar.HasItem("mail_daemon"))
444 deskbar.RemoveItem("mail_daemon");
448 void
449 MailDaemonApplication::GetNewMessages(BMessage* msg)
451 int32 account = -1;
452 if (msg->FindInt32("account", &account) == B_OK && account >= 0) {
453 // Check the single requested account
454 BInboundMailProtocol* protocol = _InboundProtocol(account);
455 if (protocol != NULL)
456 InboundMessenger(protocol).SynchronizeMessages();
457 return;
460 // Check all accounts
462 AccountMap::const_iterator iterator = fAccounts.begin();
463 for (; iterator != fAccounts.end(); iterator++) {
464 BInboundMailProtocol* protocol = iterator->second.inboundProtocol;
465 if (protocol != NULL)
466 InboundMessenger(protocol).SynchronizeMessages();
471 void
472 MailDaemonApplication::SendPendingMessages(BMessage* msg)
474 BVolumeRoster roster;
475 BVolume volume;
476 std::map<int32, send_mails_info> messages;
477 int32 account = msg->GetInt32("account", -1);
479 if (!msg->HasString("message_path")) {
480 while (roster.GetNextVolume(&volume) == B_OK) {
481 BQuery query;
482 query.SetVolume(&volume);
483 query.PushAttr(B_MAIL_ATTR_FLAGS);
484 query.PushInt32(B_MAIL_PENDING);
485 query.PushOp(B_EQ);
487 query.PushAttr(B_MAIL_ATTR_FLAGS);
488 query.PushInt32(B_MAIL_PENDING | B_MAIL_SAVE);
489 query.PushOp(B_EQ);
491 if (account >= 0) {
492 query.PushAttr(B_MAIL_ATTR_ACCOUNT_ID);
493 query.PushInt32(account);
494 query.PushOp(B_EQ);
495 query.PushOp(B_AND);
498 query.PushOp(B_OR);
499 query.Fetch();
500 BEntry entry;
501 while (query.GetNextEntry(&entry) == B_OK) {
502 if (_IsEntryInTrash(entry))
503 continue;
505 BNode node;
506 while (node.SetTo(&entry) == B_BUSY)
507 snooze(1000);
508 if (!_IsPending(node))
509 continue;
511 if (node.ReadAttr(B_MAIL_ATTR_ACCOUNT_ID, B_INT32_TYPE, 0,
512 &account, sizeof(int32)) < 0)
513 account = -1;
515 _AddMessage(messages[account], entry, node);
518 } else {
519 // Send the requested message only
520 const char* path;
521 if (msg->FindString("message_path", &path) != B_OK)
522 return;
524 BEntry entry(path);
525 _AddMessage(messages[account], entry, BNode(&entry));
528 std::map<int32, send_mails_info>::iterator iterator = messages.begin();
529 for (; iterator != messages.end(); iterator++) {
530 BOutboundMailProtocol* protocol = _OutboundProtocol(iterator->first);
531 if (protocol == NULL)
532 continue;
534 send_mails_info& info = iterator->second;
535 if (info.bytes == 0)
536 continue;
538 protocol->SendMessages(info.files, info.bytes);
543 void
544 MailDaemonApplication::MakeMimeTypes(bool remakeMIMETypes)
546 // Add MIME database entries for the e-mail file types we handle. Either
547 // do a full rebuild from nothing, or just add on the new attributes that
548 // we support which the regular BeOS mail daemon didn't have.
550 const uint8 kNTypes = 2;
551 const char* types[kNTypes] = {"text/x-email", "text/x-partial-email"};
553 for (size_t i = 0; i < kNTypes; i++) {
554 BMessage info;
555 BMimeType mime(types[i]);
556 if (mime.InitCheck() != B_OK) {
557 fputs("could not init mime type.\n", stderr);
558 return;
561 if (!mime.IsInstalled() || remakeMIMETypes) {
562 // install the full mime type
563 mime.Delete();
564 mime.Install();
566 // Set up the list of e-mail related attributes that Tracker will
567 // let you display in columns for e-mail messages.
568 addAttribute(info, B_MAIL_ATTR_NAME, "Name");
569 addAttribute(info, B_MAIL_ATTR_SUBJECT, "Subject");
570 addAttribute(info, B_MAIL_ATTR_TO, "To");
571 addAttribute(info, B_MAIL_ATTR_CC, "Cc");
572 addAttribute(info, B_MAIL_ATTR_FROM, "From");
573 addAttribute(info, B_MAIL_ATTR_REPLY, "Reply To");
574 addAttribute(info, B_MAIL_ATTR_STATUS, "Status");
575 addAttribute(info, B_MAIL_ATTR_PRIORITY, "Priority", B_STRING_TYPE,
576 true, true, 40);
577 addAttribute(info, B_MAIL_ATTR_WHEN, "When", B_TIME_TYPE, true,
578 false, 150);
579 addAttribute(info, B_MAIL_ATTR_THREAD, "Thread");
580 addAttribute(info, B_MAIL_ATTR_ACCOUNT, "Account", B_STRING_TYPE,
581 true, false, 100);
582 addAttribute(info, B_MAIL_ATTR_READ, "Read", B_INT32_TYPE,
583 true, false, 70);
584 mime.SetAttrInfo(&info);
586 if (i == 0) {
587 mime.SetShortDescription("E-mail");
588 mime.SetLongDescription("Electronic Mail Message");
589 mime.SetPreferredApp("application/x-vnd.Be-MAIL");
590 } else {
591 mime.SetShortDescription("Partial E-mail");
592 mime.SetLongDescription("A Partially Downloaded E-mail");
593 mime.SetPreferredApp("application/x-vnd.Be-MAIL");
600 void
601 MailDaemonApplication::_InitAccounts()
603 BMailAccounts accounts;
604 for (int i = 0; i < accounts.CountAccounts(); i++)
605 _InitAccount(*accounts.AccountAt(i));
609 void
610 MailDaemonApplication::_InitAccount(BMailAccountSettings& settings)
612 account_protocols account;
614 // inbound
615 if (settings.IsInboundEnabled()) {
616 account.inboundProtocol = _CreateInboundProtocol(settings,
617 account.inboundImage);
619 if (account.inboundProtocol != NULL) {
620 DefaultNotifier* notifier = new DefaultNotifier(settings.Name(), true,
621 fErrorLogWindow, fSettingsFile.ShowStatusWindow());
622 account.inboundProtocol->SetMailNotifier(notifier);
623 account.inboundProtocol->Run();
626 // outbound
627 if (settings.IsOutboundEnabled()) {
628 account.outboundProtocol = _CreateOutboundProtocol(settings,
629 account.outboundImage);
631 if (account.outboundProtocol != NULL) {
632 DefaultNotifier* notifier = new DefaultNotifier(settings.Name(), false,
633 fErrorLogWindow, fSettingsFile.ShowStatusWindow());
634 account.outboundProtocol->SetMailNotifier(notifier);
635 account.outboundProtocol->Run();
638 printf("account name %s, id %i, in %p, out %p\n", settings.Name(),
639 (int)settings.AccountID(), account.inboundProtocol,
640 account.outboundProtocol);
642 if (account.inboundProtocol != NULL || account.outboundProtocol != NULL)
643 fAccounts[settings.AccountID()] = account;
647 void
648 MailDaemonApplication::_ReloadAccounts(BMessage* message)
650 type_code typeFound;
651 int32 countFound;
652 message->GetInfo("account", &typeFound, &countFound);
653 if (typeFound != B_INT32_TYPE)
654 return;
656 // reload accounts
657 BMailAccounts accounts;
659 for (int i = 0; i < countFound; i++) {
660 int32 account = message->FindInt32("account", i);
661 AccountMap::iterator found = fAccounts.find(account);
662 if (found != fAccounts.end()) {
663 _RemoveAccount(found->second);
664 fAccounts.erase(found);
667 BMailAccountSettings* settings = accounts.AccountByID(account);
668 if (settings != NULL)
669 _InitAccount(*settings);
674 void
675 MailDaemonApplication::_RemoveAccount(const account_protocols& account)
677 if (account.inboundProtocol != NULL) {
678 account.inboundProtocol->Lock();
679 account.inboundProtocol->Quit();
681 unload_add_on(account.inboundImage);
684 if (account.outboundProtocol != NULL) {
685 account.outboundProtocol->Lock();
686 account.outboundProtocol->Quit();
688 unload_add_on(account.outboundImage);
693 BInboundMailProtocol*
694 MailDaemonApplication::_CreateInboundProtocol(BMailAccountSettings& settings,
695 image_id& image)
697 const entry_ref& entry = settings.InboundAddOnRef();
698 BInboundMailProtocol* (*instantiateProtocol)(BMailAccountSettings*);
700 BPath path(&entry);
701 image = load_add_on(path.Path());
702 if (image < 0)
703 return NULL;
705 if (get_image_symbol(image, "instantiate_inbound_protocol",
706 B_SYMBOL_TYPE_TEXT, (void**)&instantiateProtocol) != B_OK) {
707 unload_add_on(image);
708 image = -1;
709 return NULL;
711 return instantiateProtocol(&settings);
715 BOutboundMailProtocol*
716 MailDaemonApplication::_CreateOutboundProtocol(BMailAccountSettings& settings,
717 image_id& image)
719 const entry_ref& entry = settings.OutboundAddOnRef();
720 BOutboundMailProtocol* (*instantiateProtocol)(BMailAccountSettings*);
722 BPath path(&entry);
723 image = load_add_on(path.Path());
724 if (image < 0)
725 return NULL;
727 if (get_image_symbol(image, "instantiate_outbound_protocol",
728 B_SYMBOL_TYPE_TEXT, (void**)&instantiateProtocol) != B_OK) {
729 unload_add_on(image);
730 image = -1;
731 return NULL;
733 return instantiateProtocol(&settings);
737 BInboundMailProtocol*
738 MailDaemonApplication::_InboundProtocol(int32 account)
740 AccountMap::iterator found = fAccounts.find(account);
741 if (found == fAccounts.end())
742 return NULL;
743 return found->second.inboundProtocol;
747 BOutboundMailProtocol*
748 MailDaemonApplication::_OutboundProtocol(int32 account)
750 if (account < 0)
751 account = BMailSettings().DefaultOutboundAccount();
753 AccountMap::iterator found = fAccounts.find(account);
754 if (found == fAccounts.end())
755 return NULL;
756 return found->second.outboundProtocol;
760 void
761 MailDaemonApplication::_InitNewMessagesCount()
763 BVolume volume;
764 BVolumeRoster roster;
766 fNewMessages = 0;
768 while (roster.GetNextVolume(&volume) == B_OK) {
769 BQuery* query = new BQuery;
771 query->SetTarget(this);
772 query->SetVolume(&volume);
773 query->PushAttr(B_MAIL_ATTR_STATUS);
774 query->PushString("New");
775 query->PushOp(B_EQ);
776 query->PushAttr("BEOS:TYPE");
777 query->PushString("text/x-email");
778 query->PushOp(B_EQ);
779 query->PushAttr("BEOS:TYPE");
780 query->PushString("text/x-partial-email");
781 query->PushOp(B_EQ);
782 query->PushOp(B_OR);
783 query->PushOp(B_AND);
784 query->Fetch();
786 BEntry entry;
787 while (query->GetNextEntry(&entry) == B_OK)
788 fNewMessages++;
790 fQueries.AddItem(query);
795 void
796 MailDaemonApplication::_UpdateNewMessagesNotification()
798 BString title;
799 if (fNewMessages > 0) {
800 BMessageFormat format(B_TRANSLATE(
801 "{0, plural, one{One new message} other{# new messages}}"));
803 format.Format(title, fNewMessages);
804 } else
805 title = B_TRANSLATE("No new messages");
807 fNotification->SetTitle(title.String());
811 void
812 MailDaemonApplication::_UpdateAutoCheckRunner()
814 bigtime_t interval = fSettingsFile.AutoCheckInterval();
815 if (interval > 0) {
816 if (fAutoCheckRunner != NULL) {
817 fAutoCheckRunner->SetInterval(interval);
818 fAutoCheckRunner->SetCount(-1);
819 } else {
820 BMessage update(kMsgAutoCheck);
821 fAutoCheckRunner = new BMessageRunner(be_app_messenger, &update,
822 interval);
824 // Send one right away -- the message runner will wait until the
825 // first interval has passed before sending a message
826 PostMessage(&update);
828 } else {
829 delete fAutoCheckRunner;
830 fAutoCheckRunner = NULL;
835 void
836 MailDaemonApplication::_AddMessage(send_mails_info& info, const BEntry& entry,
837 const BNode& node)
839 entry_ref ref;
840 off_t size;
841 if (node.GetSize(&size) == B_OK && entry.GetRef(&ref) == B_OK) {
842 info.files.AddRef("ref", &ref);
843 info.bytes += size;
848 /*! Work-around for a broken index that contains out-of-date information.
850 /*static*/ bool
851 MailDaemonApplication::_IsPending(BNode& node)
853 int32 flags;
854 if (node.ReadAttr(B_MAIL_ATTR_FLAGS, B_INT32_TYPE, 0, &flags, sizeof(int32))
855 != (ssize_t)sizeof(int32))
856 return false;
858 return (flags & B_MAIL_PENDING) != 0;
862 /*static*/ bool
863 MailDaemonApplication::_IsEntryInTrash(BEntry& entry)
865 entry_ref ref;
866 entry.GetRef(&ref);
868 BVolume volume(ref.device);
869 BPath path;
870 if (volume.InitCheck() != B_OK
871 || find_directory(B_TRASH_DIRECTORY, &path, false, &volume) != B_OK)
872 return false;
874 BDirectory trash(path.Path());
875 return trash.Contains(&entry);