2 * Copyright 2011-2016, Haiku, Inc. All rights reserved.
3 * Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved.
14 #include <Directory.h>
16 #include <FindDirectory.h>
19 #include <NodeMonitor.h>
24 #include <StringList.h>
25 #include <VolumeRoster.h>
27 #include <MailFilter.h>
28 #include <MailDaemon.h>
29 #include <MailProtocol.h>
30 #include <MailSettings.h>
32 #include <mail_util.h>
33 #include <MailPrivate.h>
34 #include <NodeMessage.h>
36 #include "HaikuMailFormatFilter.h"
39 using namespace BPrivate
;
42 BMailProtocol::BMailProtocol(const char* name
,
43 const BMailAccountSettings
& settings
)
45 BLooper(_LooperName(name
, settings
)),
46 fAccountSettings(settings
),
49 AddFilter(new HaikuMailFormatFilter(*this, settings
));
53 BMailProtocol::~BMailProtocol()
57 for (int i
= 0; i
< fFilterList
.CountItems(); i
++)
58 delete fFilterList
.ItemAt(i
);
60 std::map
<entry_ref
, image_id
>::iterator it
= fFilterImages
.begin();
61 for (; it
!= fFilterImages
.end(); it
++)
62 unload_add_on(it
->second
);
66 const BMailAccountSettings
&
67 BMailProtocol::AccountSettings() const
69 return fAccountSettings
;
74 BMailProtocol::SetMailNotifier(BMailNotifier
* mailNotifier
)
77 fMailNotifier
= mailNotifier
;
82 BMailProtocol::MailNotifier() const
89 BMailProtocol::AddFilter(BMailFilter
* filter
)
91 BAutolock
locker(const_cast< BMailProtocol
* >(this));
92 return fFilterList
.AddItem(filter
);
97 BMailProtocol::CountFilter() const
99 BAutolock
locker(const_cast< BMailProtocol
* >(this));
100 return fFilterList
.CountItems();
105 BMailProtocol::FilterAt(int32 index
) const
107 BAutolock
locker(const_cast< BMailProtocol
* >(this));
108 return fFilterList
.ItemAt(index
);
113 BMailProtocol::RemoveFilter(int32 index
)
115 BAutolock
locker(const_cast< BMailProtocol
* >(this));
116 return fFilterList
.RemoveItemAt(index
);
121 BMailProtocol::RemoveFilter(BMailFilter
* filter
)
123 BAutolock
locker(const_cast< BMailProtocol
* >(this));
124 return fFilterList
.RemoveItem(filter
);
129 BMailProtocol::MessageReceived(BMessage
* message
)
131 BLooper::MessageReceived(message
);
136 BMailProtocol::ShowError(const char* error
)
138 if (MailNotifier() != NULL
)
139 MailNotifier()->ShowError(error
);
144 BMailProtocol::ShowMessage(const char* message
)
146 if (MailNotifier() != NULL
)
147 MailNotifier()->ShowMessage(message
);
152 BMailProtocol::SetTotalItems(uint32 items
)
154 if (MailNotifier() != NULL
)
155 MailNotifier()->SetTotalItems(items
);
160 BMailProtocol::SetTotalItemsSize(uint64 size
)
162 if (MailNotifier() != NULL
)
163 MailNotifier()->SetTotalItemsSize(size
);
168 BMailProtocol::ReportProgress(uint32 messages
, uint64 bytes
,
171 if (MailNotifier() != NULL
)
172 MailNotifier()->ReportProgress(messages
, bytes
, message
);
177 BMailProtocol::ResetProgress(const char* message
)
179 if (MailNotifier() != NULL
)
180 MailNotifier()->ResetProgress(message
);
185 BMailProtocol::NotifyNewMessagesToFetch(int32 count
)
188 SetTotalItems(count
);
193 BMailProtocol::ProcessHeaderFetched(entry_ref
& ref
, BFile
& file
,
194 BMessage
& attributes
)
196 BMailFilterAction action
= _ProcessHeaderFetched(ref
, file
, attributes
);
197 if (action
>= B_OK
&& action
!= B_DELETE_MAIL_ACTION
)
205 BMailProtocol::NotifyBodyFetched(const entry_ref
& ref
, BFile
& file
,
206 BMessage
& attributes
)
208 _NotifyBodyFetched(ref
, file
, attributes
);
214 BMailProtocol::ProcessMessageFetched(entry_ref
& ref
, BFile
& file
,
215 BMessage
& attributes
)
217 BMailFilterAction action
= _ProcessHeaderFetched(ref
, file
, attributes
);
218 if (action
>= B_OK
&& action
!= B_DELETE_MAIL_ACTION
) {
219 _NotifyBodyFetched(ref
, file
, attributes
);
228 BMailProtocol::NotifyMessageReadyToSend(const entry_ref
& ref
, BFile
& file
)
230 for (int i
= 0; i
< fFilterList
.CountItems(); i
++)
231 fFilterList
.ItemAt(i
)->MessageReadyToSend(ref
, file
);
236 BMailProtocol::NotifyMessageSent(const entry_ref
& ref
, BFile
& file
)
238 for (int i
= 0; i
< fFilterList
.CountItems(); i
++)
239 fFilterList
.ItemAt(i
)->MessageSent(ref
, file
);
244 BMailProtocol::LoadFilters(const BMailProtocolSettings
& settings
)
246 for (int i
= 0; i
< settings
.CountFilterSettings(); i
++) {
247 BMailAddOnSettings
* filterSettings
= settings
.FilterSettingsAt(i
);
248 BMailFilter
* filter
= _LoadFilter(*filterSettings
);
256 BMailProtocol::_LooperName(const char* addOnName
,
257 const BMailAccountSettings
& settings
)
259 BString name
= addOnName
;
261 const char* accountName
= settings
.Name();
262 if (accountName
!= NULL
&& accountName
[0] != '\0')
263 name
<< " " << accountName
;
270 BMailProtocol::_LoadFilter(const BMailAddOnSettings
& settings
)
272 const entry_ref
& ref
= settings
.AddOnRef();
273 std::map
<entry_ref
, image_id
>::iterator it
= fFilterImages
.find(ref
);
275 if (it
!= fFilterImages
.end())
280 image
= load_add_on(path
.Path());
285 BMailFilter
* (*instantiateFilter
)(BMailProtocol
& protocol
,
286 const BMailAddOnSettings
& settings
);
287 if (get_image_symbol(image
, "instantiate_filter", B_SYMBOL_TYPE_TEXT
,
288 (void**)&instantiateFilter
) != B_OK
) {
289 unload_add_on(image
);
293 fFilterImages
[ref
] = image
;
294 return instantiateFilter(*this, settings
);
299 BMailProtocol::_ProcessHeaderFetched(entry_ref
& ref
, BFile
& file
,
300 BMessage
& attributes
)
302 entry_ref outRef
= ref
;
304 for (int i
= 0; i
< fFilterList
.CountItems(); i
++) {
305 BMailFilterAction action
= fFilterList
.ItemAt(i
)->HeaderFetched(outRef
,
307 if (action
== B_DELETE_MAIL_ACTION
) {
308 // We have to delete the message
310 status_t status
= entry
.Remove();
311 if (status
!= B_OK
) {
312 fprintf(stderr
, "BMailProtocol::NotifyHeaderFetched(): could "
313 "not delete mail: %s\n", strerror(status
));
315 return B_DELETE_MAIL_ACTION
;
320 return B_NO_MAIL_ACTION
;
322 // We have to rename the file
323 node_ref newParentRef
;
324 newParentRef
.device
= outRef
.device
;
325 newParentRef
.node
= outRef
.directory
;
327 BDirectory
newParent(&newParentRef
);
328 status_t status
= newParent
.InitCheck();
330 if (status
== B_OK
) {
331 int32 uniqueNumber
= 1;
333 workerName
= outRef
.name
;
334 if (uniqueNumber
> 1)
335 workerName
<< "_" << uniqueNumber
;
337 // TODO: support copying to another device!
339 status
= entry
.Rename(workerName
);
342 } while (status
== B_FILE_EXISTS
);
345 if (status
!= B_OK
) {
346 fprintf(stderr
, "BMailProtocol::NotifyHeaderFetched(): could not "
347 "rename mail (%s)! (should be: %s)\n", strerror(status
),
348 workerName
.String());
352 ref
.set_name(workerName
.String());
354 return B_MOVE_MAIL_ACTION
;
359 BMailProtocol::_NotifyBodyFetched(const entry_ref
& ref
, BFile
& file
,
360 BMessage
& attributes
)
362 for (int i
= 0; i
< fFilterList
.CountItems(); i
++)
363 fFilterList
.ItemAt(i
)->BodyFetched(ref
, file
, attributes
);
370 BInboundMailProtocol::BInboundMailProtocol(const char* name
,
371 const BMailAccountSettings
& settings
)
373 BMailProtocol(name
, settings
)
375 LoadFilters(fAccountSettings
.InboundSettings());
379 BInboundMailProtocol::~BInboundMailProtocol()
385 BInboundMailProtocol::MessageReceived(BMessage
* message
)
387 switch (message
->what
) {
388 case kMsgSyncMessages
:
390 NotiyMailboxSynchronized(SyncMessages());
397 if (message
->FindRef("ref", &ref
) != B_OK
)
401 message
->FindMessenger("target", &target
);
403 status_t status
= HandleFetchBody(ref
, target
);
405 ReplyBodyFetched(target
, ref
, status
);
409 case kMsgMarkMessageAsRead
:
412 message
->FindRef("ref", &ref
);
413 read_flags read
= (read_flags
)message
->FindInt32("read");
414 MarkMessageAsRead(ref
, read
);
419 BMailProtocol::MessageReceived(message
);
426 BInboundMailProtocol::FetchBody(const entry_ref
& ref
, BMessenger
* replyTo
)
428 BMessage
message(kMsgFetchBody
);
429 message
.AddRef("ref", &ref
);
431 message
.AddMessenger("target", *replyTo
);
433 return BMessenger(this).SendMessage(&message
);
438 BInboundMailProtocol::MarkMessageAsRead(const entry_ref
& ref
, read_flags flag
)
441 return write_read_attr(node
, flag
);
446 BInboundMailProtocol::ReplyBodyFetched(const BMessenger
& replyTo
,
447 const entry_ref
& ref
, status_t status
)
449 BMessage
message(B_MAIL_BODY_FETCHED
);
450 message
.AddInt32("status", status
);
451 message
.AddRef("ref", &ref
);
452 replyTo
.SendMessage(&message
);
457 BInboundMailProtocol::NotiyMailboxSynchronized(status_t status
)
459 for (int32 i
= 0; i
< CountFilter(); i
++)
460 FilterAt(i
)->MailboxSynchronized(status
);
467 BOutboundMailProtocol::BOutboundMailProtocol(const char* name
,
468 const BMailAccountSettings
& settings
)
470 BMailProtocol(name
, settings
)
472 LoadFilters(fAccountSettings
.OutboundSettings());
476 BOutboundMailProtocol::~BOutboundMailProtocol()
482 BOutboundMailProtocol::SendMessages(const BMessage
& files
, off_t totalBytes
)
484 BMessage
message(kMsgSendMessages
);
485 message
.Append(files
);
486 message
.AddInt64("bytes", totalBytes
);
488 return BMessenger(this).SendMessage(&message
);
493 BOutboundMailProtocol::MessageReceived(BMessage
* message
)
495 switch (message
->what
) {
496 case kMsgSendMessages
:
497 HandleSendMessages(*message
, message
->FindInt64("bytes"));
501 BMailProtocol::MessageReceived(message
);