diff --git a/src/servers/mail/MailDaemon.cpp b/src/servers/mail/MailDaemon.cpp index ba7e998003..688b28d86b 100644 --- a/src/servers/mail/MailDaemon.cpp +++ b/src/servers/mail/MailDaemon.cpp @@ -35,7 +35,21 @@ #define B_TRANSLATE_CONTEXT "MailDaemon" -void +struct send_mails_info { + send_mails_info() + { + totalSize = 0; + } + + vector files; + off_t totalSize; +}; + + +// #pragma mark - + + +static void makeIndices() { const char* stringIndices[] = { @@ -67,7 +81,7 @@ makeIndices() } -void +static void addAttribute(BMessage& msg, const char* name, const char* publicName, int32 type = B_STRING_TYPE, bool viewable = true, bool editable = false, int32 width = 200) @@ -212,6 +226,406 @@ MailDaemonApp::RefsReceived(BMessage* message) } +void +MailDaemonApp::MessageReceived(BMessage* msg) +{ + switch (msg->what) { + case 'moto': + if (fSettingsFile.CheckOnlyIfPPPUp()) { + // TODO: check whether internet is up and running! + } + // supposed to fall through + case kMsgCheckAndSend: // check & send messages + msg->what = kMsgSendMessages; + PostMessage(msg); + // supposed to fall trough + case kMsgCheckMessage: // check messages + GetNewMessages(msg); + break; + + case kMsgSendMessages: // send messages + SendPendingMessages(msg); + break; + + case kMsgSettingsUpdated: + fSettingsFile.Reload(); + _UpdateAutoCheck(fSettingsFile.AutoCheckInterval()); + fMailStatusWindow->SetShowCriterion(fSettingsFile.ShowStatusWindow()); + break; + + case kMsgAccountsChanged: + _ReloadAccounts(msg); + break; + + case kMsgSetStatusWindowMode: // when to show the status window + { + int32 mode; + if (msg->FindInt32("ShowStatusWindow", &mode) == B_OK) + fMailStatusWindow->SetShowCriterion(mode); + break; + } + + case kMsgMarkMessageAsRead: + { + int32 account = msg->FindInt32("account"); + entry_ref ref; + if (msg->FindRef("ref", &ref) != B_OK) + break; + read_flags read = (read_flags)msg->FindInt32("read"); + AccountMap::iterator it = fAccounts.find(account); + if (it == fAccounts.end()) + break; + InboundProtocolThread* inboundThread = it->second.inboundThread; + inboundThread->MarkMessageAsRead(ref, read); + break; + } + + case kMsgFetchBody: + RefsReceived(msg); + break; + + case 'lkch': // status window look changed + case 'wsch': // workspace changed + fMailStatusWindow->PostMessage(msg); + break; + + case 'stwg': // Status window gone + { + BMessage reply('mnuc'); + reply.AddInt32("num_new_messages", fNewMessages); + + while ((msg = fFetchDoneRespondents.RemoveItemAt(0))) { + msg->SendReply(&reply); + delete msg; + } + + if (fAlertString != B_EMPTY_STRING) { + fAlertString.Truncate(fAlertString.Length() - 1); + BAlert* alert = new BAlert(B_TRANSLATE("New Messages"), + fAlertString.String(), "OK", NULL, NULL, B_WIDTH_AS_USUAL); + alert->SetFeel(B_NORMAL_WINDOW_FEEL); + alert->Go(NULL); + fAlertString = B_EMPTY_STRING; + } + + if (fCentralBeep) { + system_beep("New E-mail"); + fCentralBeep = false; + } + break; + } + + case 'mcbp': + if (fNewMessages > 0) + fCentralBeep = true; + break; + + case kMsgCountNewMessages: // Number of new messages + { + BMessage reply('mnuc'); // Mail New message Count + if (msg->FindBool("wait_for_fetch_done")) { + fFetchDoneRespondents.AddItem(DetachCurrentMessage()); + break; + } + + reply.AddInt32("num_new_messages", fNewMessages); + msg->SendReply(&reply); + break; + } + + case 'mblk': // Mail Blink + if (fNewMessages > 0) + fLEDAnimation->Start(); + break; + + case 'enda': // End Auto Check + delete fAutoCheckRunner; + fAutoCheckRunner = NULL; + break; + + case 'numg': + { + int32 numMessages = msg->FindInt32("num_messages"); + BString numString; + + if (numMessages > 1) + fAlertString << B_TRANSLATE("%num new messages for %name\n"); + else + fAlertString << B_TRANSLATE("%num new message for %name\n"); + + numString << numMessages; + fAlertString.ReplaceFirst("%num", numString); + fAlertString.ReplaceFirst("%name", msg->FindString("name")); + break; + } + + case B_QUERY_UPDATE: + { + int32 what; + msg->FindInt32("opcode", &what); + switch (what) { + case B_ENTRY_CREATED: + fNewMessages++; + break; + case B_ENTRY_REMOVED: + fNewMessages--; + break; + } + + BString string, numString; + + if (fNewMessages > 0) { + if (fNewMessages != 1) + string << B_TRANSLATE("%num new messages."); + else + string << B_TRANSLATE("%num new message."); + + numString << fNewMessages; + string.ReplaceFirst("%num", numString); + } + else + string << B_TRANSLATE("No new messages."); + + fMailStatusWindow->SetDefaultMessage(string.String()); + break; + } + + default: + BApplication::MessageReceived(msg); + break; + } +} + + +void +MailDaemonApp::Pulse() +{ + bigtime_t idle = idle_time(); + if (fLEDAnimation->IsRunning() && idle < 100000) + fLEDAnimation->Stop(); +} + + +bool +MailDaemonApp::QuitRequested() +{ + RemoveDeskbarIcon(); + return true; +} + + +void +MailDaemonApp::InstallDeskbarIcon() +{ + BDeskbar deskbar; + + if (!deskbar.HasItem("mail_daemon")) { + BRoster roster; + entry_ref ref; + + status_t status = roster.FindApp("application/x-vnd.Be-POST", &ref); + if (status < B_OK) { + fprintf(stderr, "Can't find application to tell deskbar: %s\n", + strerror(status)); + return; + } + + status = deskbar.AddItem(&ref); + if (status < B_OK) { + fprintf(stderr, "Can't add deskbar replicant: %s\n", strerror(status)); + return; + } + } +} + + +void +MailDaemonApp::RemoveDeskbarIcon() +{ + BDeskbar deskbar; + if (deskbar.HasItem("mail_daemon")) + deskbar.RemoveItem("mail_daemon"); +} + + +void +MailDaemonApp::GetNewMessages(BMessage* msg) +{ + int32 account = -1; + if (msg->FindInt32("account", &account) == B_OK && account >= 0) { + InboundProtocolThread* protocol = _FindInboundProtocol(account); + if (!protocol) + return; + protocol->SyncMessages(); + return; + } + + // else check all accounts + AccountMap::const_iterator it = fAccounts.begin(); + for (; it != fAccounts.end(); it++) { + InboundProtocolThread* protocol = it->second.inboundThread; + if (!protocol) + continue; + protocol->SyncMessages(); + } +} + + +void +MailDaemonApp::SendPendingMessages(BMessage* msg) +{ + BVolumeRoster roster; + BVolume volume; + + map messages; + + + int32 account = -1; + if (msg->FindInt32("account", &account) != B_OK) + account = -1; + + if (!msg->HasString("message_path")) { + while (roster.GetNextVolume(&volume) == B_OK) { + BQuery query; + query.SetVolume(&volume); + query.PushAttr(B_MAIL_ATTR_FLAGS); + query.PushInt32(B_MAIL_PENDING); + query.PushOp(B_EQ); + + query.PushAttr(B_MAIL_ATTR_FLAGS); + query.PushInt32(B_MAIL_PENDING | B_MAIL_SAVE); + query.PushOp(B_EQ); + + if (account >= 0) { + query.PushAttr(B_MAIL_ATTR_ACCOUNT_ID); + query.PushInt32(account); + query.PushOp(B_EQ); + query.PushOp(B_AND); + } + + query.PushOp(B_OR); + query.Fetch(); + BEntry entry; + while (query.GetNextEntry(&entry) == B_OK) { + if (_IsEntryInTrash(entry)) + continue; + + BNode node; + while (node.SetTo(&entry) == B_BUSY) + snooze(1000); + if (!_IsPending(node)) + continue; + + int32 messageAccount; + if (node.ReadAttr(B_MAIL_ATTR_ACCOUNT_ID, B_INT32_TYPE, 0, + &messageAccount, sizeof(int32)) < 0) + messageAccount = -1; + + off_t size = 0; + node.GetSize(&size); + entry_ref ref; + entry.GetRef(&ref); + + messages[messageAccount].files.push_back(ref); + messages[messageAccount].totalSize += size; + } + } + } else { + const char* path; + if (msg->FindString("message_path", &path) != B_OK) + return; + + off_t size = 0; + if (BNode(path).GetSize(&size) != B_OK) + return; + BEntry entry(path); + entry_ref ref; + entry.GetRef(&ref); + + messages[account].files.push_back(ref); + messages[account].totalSize += size; + } + + map::iterator iter = messages.begin(); + for (; iter != messages.end(); iter++) { + OutboundProtocolThread* protocolThread = _FindOutboundProtocol( + iter->first); + if (!protocolThread) + continue; + + send_mails_info& info = iter->second; + if (info.files.size() == 0) + continue; + + MailProtocol* protocol = protocolThread->Protocol(); + + protocolThread->Lock(); + protocol->SetTotalItems(info.files.size()); + protocol->SetTotalItemsSize(info.totalSize); + protocolThread->Unlock(); + + protocolThread->SendMessages(iter->second.files, info.totalSize); + } +} + + +void +MailDaemonApp::MakeMimeTypes(bool remakeMIMETypes) +{ + // Add MIME database entries for the e-mail file types we handle. Either + // do a full rebuild from nothing, or just add on the new attributes that + // we support which the regular BeOS mail daemon didn't have. + + const uint8 kNTypes = 2; + const char* types[kNTypes] = {"text/x-email", "text/x-partial-email"}; + + for (size_t i = 0; i < kNTypes; i++) { + BMessage info; + BMimeType mime(types[i]); + if (mime.InitCheck() != B_OK) { + fputs("could not init mime type.\n", stderr); + return; + } + + if (!mime.IsInstalled() || remakeMIMETypes) { + // install the full mime type + mime.Delete(); + mime.Install(); + + // Set up the list of e-mail related attributes that Tracker will + // let you display in columns for e-mail messages. + addAttribute(info, B_MAIL_ATTR_NAME, "Name"); + addAttribute(info, B_MAIL_ATTR_SUBJECT, "Subject"); + addAttribute(info, B_MAIL_ATTR_TO, "To"); + addAttribute(info, B_MAIL_ATTR_CC, "Cc"); + addAttribute(info, B_MAIL_ATTR_FROM, "From"); + addAttribute(info, B_MAIL_ATTR_REPLY, "Reply To"); + addAttribute(info, B_MAIL_ATTR_STATUS, "Status"); + addAttribute(info, B_MAIL_ATTR_PRIORITY, "Priority", B_STRING_TYPE, + true, true, 40); + addAttribute(info, B_MAIL_ATTR_WHEN, "When", B_TIME_TYPE, true, + false, 150); + addAttribute(info, B_MAIL_ATTR_THREAD, "Thread"); + addAttribute(info, B_MAIL_ATTR_ACCOUNT, "Account", B_STRING_TYPE, + true, false, 100); + addAttribute(info, B_MAIL_ATTR_READ, "Read", B_INT32_TYPE, + true, false, 70); + mime.SetAttrInfo(&info); + + if (i == 0) { + mime.SetShortDescription("E-mail"); + mime.SetLongDescription("Electronic Mail Message"); + mime.SetPreferredApp("application/x-vnd.Be-MAIL"); + } else { + mime.SetShortDescription("Partial E-mail"); + mime.SetLongDescription("A Partially Downloaded E-mail"); + mime.SetPreferredApp("application/x-vnd.Be-MAIL"); + } + } + } +} + + void MailDaemonApp::_InitAccounts() { @@ -400,423 +814,9 @@ MailDaemonApp::_UpdateAutoCheck(bigtime_t interval) } -void -MailDaemonApp::MessageReceived(BMessage* msg) -{ - switch (msg->what) { - case 'moto': - if (fSettingsFile.CheckOnlyIfPPPUp()) { - // TODO: check whether internet is up and running! - } - // supposed to fall through - case kMsgCheckAndSend: // check & send messages - msg->what = kMsgSendMessages; - PostMessage(msg); - // supposed to fall trough - case kMsgCheckMessage: // check messages - GetNewMessages(msg); - break; - - case kMsgSendMessages: // send messages - SendPendingMessages(msg); - break; - - case kMsgSettingsUpdated: - fSettingsFile.Reload(); - _UpdateAutoCheck(fSettingsFile.AutoCheckInterval()); - fMailStatusWindow->SetShowCriterion(fSettingsFile.ShowStatusWindow()); - break; - - case kMsgAccountsChanged: - _ReloadAccounts(msg); - break; - - case kMsgSetStatusWindowMode: // when to show the status window - { - int32 mode; - if (msg->FindInt32("ShowStatusWindow", &mode) == B_OK) - fMailStatusWindow->SetShowCriterion(mode); - break; - } - - case kMsgMarkMessageAsRead: - { - int32 account = msg->FindInt32("account"); - entry_ref ref; - if (msg->FindRef("ref", &ref) != B_OK) - break; - read_flags read = (read_flags)msg->FindInt32("read"); - AccountMap::iterator it = fAccounts.find(account); - if (it == fAccounts.end()) - break; - InboundProtocolThread* inboundThread = it->second.inboundThread; - inboundThread->MarkMessageAsRead(ref, read); - break; - } - - case kMsgFetchBody: - RefsReceived(msg); - break; - - case 'lkch': // status window look changed - case 'wsch': // workspace changed - fMailStatusWindow->PostMessage(msg); - break; - - case 'stwg': // Status window gone - { - BMessage reply('mnuc'); - reply.AddInt32("num_new_messages", fNewMessages); - - while ((msg = fFetchDoneRespondents.RemoveItemAt(0))) { - msg->SendReply(&reply); - delete msg; - } - - if (fAlertString != B_EMPTY_STRING) { - fAlertString.Truncate(fAlertString.Length() - 1); - BAlert* alert = new BAlert(B_TRANSLATE("New Messages"), - fAlertString.String(), "OK", NULL, NULL, B_WIDTH_AS_USUAL); - alert->SetFeel(B_NORMAL_WINDOW_FEEL); - alert->Go(NULL); - fAlertString = B_EMPTY_STRING; - } - - if (fCentralBeep) { - system_beep("New E-mail"); - fCentralBeep = false; - } - break; - } - - case 'mcbp': - if (fNewMessages > 0) - fCentralBeep = true; - break; - - case kMsgCountNewMessages: // Number of new messages - { - BMessage reply('mnuc'); // Mail New message Count - if (msg->FindBool("wait_for_fetch_done")) { - fFetchDoneRespondents.AddItem(DetachCurrentMessage()); - break; - } - - reply.AddInt32("num_new_messages", fNewMessages); - msg->SendReply(&reply); - break; - } - - case 'mblk': // Mail Blink - if (fNewMessages > 0) - fLEDAnimation->Start(); - break; - - case 'enda': // End Auto Check - delete fAutoCheckRunner; - fAutoCheckRunner = NULL; - break; - - case 'numg': - { - int32 numMessages = msg->FindInt32("num_messages"); - BString numString; - - if (numMessages > 1) - fAlertString << B_TRANSLATE("%num new messages for %name\n"); - else - fAlertString << B_TRANSLATE("%num new message for %name\n"); - - numString << numMessages; - fAlertString.ReplaceFirst("%num", numString); - fAlertString.ReplaceFirst("%name", msg->FindString("name")); - break; - } - - case B_QUERY_UPDATE: - { - int32 what; - msg->FindInt32("opcode", &what); - switch (what) { - case B_ENTRY_CREATED: - fNewMessages++; - break; - case B_ENTRY_REMOVED: - fNewMessages--; - break; - } - - BString string, numString; - - if (fNewMessages > 0) { - if (fNewMessages != 1) - string << B_TRANSLATE("%num new messages."); - else - string << B_TRANSLATE("%num new message."); - - numString << fNewMessages; - string.ReplaceFirst("%num", numString); - } - else - string << B_TRANSLATE("No new messages."); - - fMailStatusWindow->SetDefaultMessage(string.String()); - break; - } - - default: - BApplication::MessageReceived(msg); - break; - } -} - - -void -MailDaemonApp::InstallDeskbarIcon() -{ - BDeskbar deskbar; - - if (!deskbar.HasItem("mail_daemon")) { - BRoster roster; - entry_ref ref; - - status_t status = roster.FindApp("application/x-vnd.Be-POST", &ref); - if (status < B_OK) { - fprintf(stderr, "Can't find application to tell deskbar: %s\n", - strerror(status)); - return; - } - - status = deskbar.AddItem(&ref); - if (status < B_OK) { - fprintf(stderr, "Can't add deskbar replicant: %s\n", strerror(status)); - return; - } - } -} - - -void -MailDaemonApp::RemoveDeskbarIcon() -{ - BDeskbar deskbar; - if (deskbar.HasItem("mail_daemon")) - deskbar.RemoveItem("mail_daemon"); -} - - -bool -MailDaemonApp::QuitRequested() -{ - RemoveDeskbarIcon(); - - return true; -} - - -void -MailDaemonApp::GetNewMessages(BMessage* msg) -{ - int32 account = -1; - if (msg->FindInt32("account", &account) == B_OK && account >= 0) { - InboundProtocolThread* protocol = _FindInboundProtocol(account); - if (!protocol) - return; - protocol->SyncMessages(); - return; - } - - // else check all accounts - AccountMap::const_iterator it = fAccounts.begin(); - for (; it != fAccounts.end(); it++) { - InboundProtocolThread* protocol = it->second.inboundThread; - if (!protocol) - continue; - protocol->SyncMessages(); - } -} - - -void -MailDaemonApp::MakeMimeTypes(bool remakeMIMETypes) -{ - // Add MIME database entries for the e-mail file types we handle. Either - // do a full rebuild from nothing, or just add on the new attributes that - // we support which the regular BeOS mail daemon didn't have. - - const uint8 kNTypes = 2; - const char* types[kNTypes] = {"text/x-email", "text/x-partial-email"}; - - for (size_t i = 0; i < kNTypes; i++) { - BMessage info; - BMimeType mime(types[i]); - if (mime.InitCheck() != B_OK) { - fputs("could not init mime type.\n", stderr); - return; - } - - if (!mime.IsInstalled() || remakeMIMETypes) { - // install the full mime type - mime.Delete(); - mime.Install(); - - // Set up the list of e-mail related attributes that Tracker will - // let you display in columns for e-mail messages. - addAttribute(info, B_MAIL_ATTR_NAME, "Name"); - addAttribute(info, B_MAIL_ATTR_SUBJECT, "Subject"); - addAttribute(info, B_MAIL_ATTR_TO, "To"); - addAttribute(info, B_MAIL_ATTR_CC, "Cc"); - addAttribute(info, B_MAIL_ATTR_FROM, "From"); - addAttribute(info, B_MAIL_ATTR_REPLY, "Reply To"); - addAttribute(info, B_MAIL_ATTR_STATUS, "Status"); - addAttribute(info, B_MAIL_ATTR_PRIORITY, "Priority", B_STRING_TYPE, - true, true, 40); - addAttribute(info, B_MAIL_ATTR_WHEN, "When", B_TIME_TYPE, true, - false, 150); - addAttribute(info, B_MAIL_ATTR_THREAD, "Thread"); - addAttribute(info, B_MAIL_ATTR_ACCOUNT, "Account", B_STRING_TYPE, - true, false, 100); - addAttribute(info, B_MAIL_ATTR_READ, "Read", B_INT32_TYPE, - true, false, 70); - mime.SetAttrInfo(&info); - - if (i == 0) { - mime.SetShortDescription("E-mail"); - mime.SetLongDescription("Electronic Mail Message"); - mime.SetPreferredApp("application/x-vnd.Be-MAIL"); - } else { - mime.SetShortDescription("Partial E-mail"); - mime.SetLongDescription("A Partially Downloaded E-mail"); - mime.SetPreferredApp("application/x-vnd.Be-MAIL"); - } - } - } -} - - -struct send_mails_info { - send_mails_info() - { - totalSize = 0; - } - vector files; - off_t totalSize; -}; - - -void -MailDaemonApp::SendPendingMessages(BMessage* msg) -{ - BVolumeRoster roster; - BVolume volume; - - map messages; - - - int32 account = -1; - if (msg->FindInt32("account", &account) != B_OK) - account = -1; - - if (!msg->HasString("message_path")) { - while (roster.GetNextVolume(&volume) == B_OK) { - BQuery query; - query.SetVolume(&volume); - query.PushAttr(B_MAIL_ATTR_FLAGS); - query.PushInt32(B_MAIL_PENDING); - query.PushOp(B_EQ); - - query.PushAttr(B_MAIL_ATTR_FLAGS); - query.PushInt32(B_MAIL_PENDING | B_MAIL_SAVE); - query.PushOp(B_EQ); - - if (account >= 0) { - query.PushAttr(B_MAIL_ATTR_ACCOUNT_ID); - query.PushInt32(account); - query.PushOp(B_EQ); - query.PushOp(B_AND); - } - - query.PushOp(B_OR); - query.Fetch(); - BEntry entry; - while (query.GetNextEntry(&entry) == B_OK) { - if (_IsEntryInTrash(entry)) - continue; - - BNode node; - while (node.SetTo(&entry) == B_BUSY) - snooze(1000); - if (!_IsPending(node)) - continue; - - int32 messageAccount; - if (node.ReadAttr(B_MAIL_ATTR_ACCOUNT_ID, B_INT32_TYPE, 0, - &messageAccount, sizeof(int32)) < 0) - messageAccount = -1; - - off_t size = 0; - node.GetSize(&size); - entry_ref ref; - entry.GetRef(&ref); - - messages[messageAccount].files.push_back(ref); - messages[messageAccount].totalSize += size; - } - } - } else { - const char* path; - if (msg->FindString("message_path", &path) != B_OK) - return; - - off_t size = 0; - if (BNode(path).GetSize(&size) != B_OK) - return; - BEntry entry(path); - entry_ref ref; - entry.GetRef(&ref); - - messages[account].files.push_back(ref); - messages[account].totalSize += size; - } - - map::iterator iter = messages.begin(); - for (; iter != messages.end(); iter++) { - OutboundProtocolThread* protocolThread = _FindOutboundProtocol( - iter->first); - if (!protocolThread) - continue; - - send_mails_info& info = iter->second; - if (info.files.size() == 0) - continue; - - MailProtocol* protocol = protocolThread->Protocol(); - - protocolThread->Lock(); - protocol->SetTotalItems(info.files.size()); - protocol->SetTotalItemsSize(info.totalSize); - protocolThread->Unlock(); - - protocolThread->SendMessages(iter->second.files, info.totalSize); - } - -} - - -void -MailDaemonApp::Pulse() -{ - bigtime_t idle = idle_time(); - if (fLEDAnimation->IsRunning() && idle < 100000) - fLEDAnimation->Stop(); -} - - /*! Work-around for a broken index that contains out-of-date information. */ - -/* static */ -bool +/*static*/ bool MailDaemonApp::_IsPending(BNode& node) { int32 flags; @@ -828,8 +828,7 @@ MailDaemonApp::_IsPending(BNode& node) } -/* static */ -bool +/*static*/ bool MailDaemonApp::_IsEntryInTrash(BEntry& entry) { entry_ref ref; diff --git a/src/servers/mail/MailDaemon.h b/src/servers/mail/MailDaemon.h index 82a0721d80..212c1f7c01 100644 --- a/src/servers/mail/MailDaemon.h +++ b/src/servers/mail/MailDaemon.h @@ -50,18 +50,18 @@ public: MailDaemonApp(); virtual ~MailDaemonApp(); - virtual void MessageReceived(BMessage* message); + virtual void ReadyToRun(); virtual void RefsReceived(BMessage* message); + virtual void MessageReceived(BMessage* message); virtual void Pulse(); virtual bool QuitRequested(); - virtual void ReadyToRun(); void InstallDeskbarIcon(); void RemoveDeskbarIcon(); - void SendPendingMessages(BMessage* message); void GetNewMessages(BMessage* message); + void SendPendingMessages(BMessage* message); void MakeMimeTypes(bool remakeMIMETypes = false); @@ -82,6 +82,7 @@ private: OutboundProtocolThread* _FindOutboundProtocol(int32 account); void _UpdateAutoCheck(bigtime_t interval); + static bool _IsPending(BNode& node); static bool _IsEntryInTrash(BEntry& entry); @@ -97,8 +98,8 @@ private: // account. // Set to TRUE by the 'mcbp' message that the mail Notification // filter sends us, cleared when the beep is done. - BObjectList fFetchDoneRespondents; - BObjectList fQueries; + BObjectList fFetchDoneRespondents; + BObjectList fQueries; LEDAnimation* fLEDAnimation;