2 * Copyright 2011-2013, Haiku, Inc. All rights reserved.
3 * Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved.
14 #include <Directory.h>
15 #include <FindDirectory.h>
20 #include <NodeMonitor.h>
25 #include <StringList.h>
26 #include <VolumeRoster.h>
28 #include <MailFilter.h>
29 #include <MailDaemon.h>
30 #include <MailProtocol.h>
31 #include <MailSettings.h>
33 #include <mail_util.h>
34 #include <MailPrivate.h>
35 #include <NodeMessage.h>
37 #include "HaikuMailFormatFilter.h"
40 using namespace BPrivate
;
43 const uint32 kMsgDeleteMessage
= '&DeM';
44 const uint32 kMsgAppendMessage
= '&ApM';
46 const uint32 kMsgSendMessage
= '&SeM';
49 BMailProtocol::BMailProtocol(const BMailAccountSettings
& settings
)
51 fAccountSettings(settings
),
54 AddFilter(new HaikuMailFormatFilter(*this, settings
));
58 BMailProtocol::~BMailProtocol()
62 for (int i
= 0; i
< fFilterList
.CountItems(); i
++)
63 delete fFilterList
.ItemAt(i
);
65 std::map
<entry_ref
, image_id
>::iterator it
= fFilterImages
.begin();
66 for (; it
!= fFilterImages
.end(); it
++)
67 unload_add_on(it
->second
);
71 const BMailAccountSettings
&
72 BMailProtocol::AccountSettings() const
74 return fAccountSettings
;
79 BMailProtocol::SetMailNotifier(BMailNotifier
* mailNotifier
)
82 fMailNotifier
= mailNotifier
;
87 BMailProtocol::MailNotifier() const
94 BMailProtocol::AddFilter(BMailFilter
* filter
)
97 return fFilterList
.AddItem(filter
);
102 BMailProtocol::CountFilter() const
104 BLocker
locker(this);
105 return fFilterList
.CountItems();
110 BMailProtocol::FilterAt(int32 index
) const
112 BLocker
locker(this);
113 return fFilterList
.ItemAt(index
);
118 BMailProtocol::RemoveFilter(int32 index
)
120 BLocker
locker(this);
121 return fFilterList
.RemoveItemAt(index
);
126 BMailProtocol::RemoveFilter(BMailFilter
* filter
)
128 BLocker
locker(this);
129 return fFilterList
.RemoveItem(filter
);
134 BMailProtocol::MessageReceived(BMessage
* message
)
136 BLooper::MessageReceived(message
);
141 BMailProtocol::MoveMessage(const entry_ref
& ref
, BDirectory
& dir
)
144 return entry
.MoveTo(&dir
);
149 BMailProtocol::DeleteMessage(const entry_ref
& ref
)
152 return entry
.Remove();
157 BMailProtocol::ShowError(const char* error
)
159 if (MailNotifier() != NULL
)
160 MailNotifier()->ShowError(error
);
165 BMailProtocol::ShowMessage(const char* message
)
167 if (MailNotifier() != NULL
)
168 MailNotifier()->ShowMessage(message
);
173 BMailProtocol::SetTotalItems(uint32 items
)
175 if (MailNotifier() != NULL
)
176 MailNotifier()->SetTotalItems(items
);
181 BMailProtocol::SetTotalItemsSize(uint64 size
)
183 if (MailNotifier() != NULL
)
184 MailNotifier()->SetTotalItemsSize(size
);
189 BMailProtocol::ReportProgress(uint32 messages
, uint64 bytes
,
192 if (MailNotifier() != NULL
)
193 MailNotifier()->ReportProgress(messages
, bytes
, message
);
198 BMailProtocol::ResetProgress(const char* message
)
200 if (MailNotifier() != NULL
)
201 MailNotifier()->ResetProgress(message
);
206 BMailProtocol::NotifyNewMessagesToFetch(int32 count
)
209 SetTotalItems(count
);
214 BMailProtocol::ProcessHeaderFetched(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
)
226 BMailProtocol::NotifyBodyFetched(const entry_ref
& ref
, BFile
& file
,
227 BMessage
& attributes
)
229 _NotifyBodyFetched(ref
, file
, attributes
);
235 BMailProtocol::ProcessMessageFetched(entry_ref
& ref
, BFile
& file
,
236 BMessage
& attributes
)
238 BMailFilterAction action
= _ProcessHeaderFetched(ref
, file
, attributes
);
239 if (action
>= B_OK
&& action
!= B_DELETE_MAIL_ACTION
) {
240 _NotifyBodyFetched(ref
, file
, attributes
);
249 BMailProtocol::NotifyMessageReadyToSend(const entry_ref
& ref
, BFile
& file
)
251 for (int i
= 0; i
< fFilterList
.CountItems(); i
++)
252 fFilterList
.ItemAt(i
)->MessageReadyToSend(ref
, file
);
257 BMailProtocol::NotifyMessageSent(const entry_ref
& ref
, BFile
& file
)
259 for (int i
= 0; i
< fFilterList
.CountItems(); i
++)
260 fFilterList
.ItemAt(i
)->MessageSent(ref
, file
);
265 BMailProtocol::LoadFilters(const BMailProtocolSettings
& settings
)
267 for (int i
= 0; i
< settings
.CountFilterSettings(); i
++) {
268 BMailAddOnSettings
* filterSettings
= settings
.FilterSettingsAt(i
);
269 BMailFilter
* filter
= _LoadFilter(*filterSettings
);
277 BMailProtocol::_LoadFilter(const BMailAddOnSettings
& settings
)
279 const entry_ref
& ref
= settings
.AddOnRef();
280 std::map
<entry_ref
, image_id
>::iterator it
= fFilterImages
.find(ref
);
282 if (it
!= fFilterImages
.end())
287 image
= load_add_on(path
.Path());
292 BMailFilter
* (*instantiateFilter
)(BMailProtocol
& protocol
,
293 const BMailAddOnSettings
& settings
);
294 if (get_image_symbol(image
, "instantiate_filter", B_SYMBOL_TYPE_TEXT
,
295 (void**)&instantiateFilter
) != B_OK
) {
296 unload_add_on(image
);
300 fFilterImages
[ref
] = image
;
301 return instantiateFilter(*this, settings
);
306 BMailProtocol::_ProcessHeaderFetched(entry_ref
& ref
, BFile
& file
,
307 BMessage
& attributes
)
309 entry_ref outRef
= ref
;
311 for (int i
= 0; i
< fFilterList
.CountItems(); i
++) {
312 BMailFilterAction action
= fFilterList
.ItemAt(i
)->HeaderFetched(outRef
,
314 if (action
== B_DELETE_MAIL_ACTION
) {
315 // We have to delete the message
317 status_t status
= entry
.Remove();
318 if (status
!= B_OK
) {
319 fprintf(stderr
, "BMailProtocol::NotifyHeaderFetched(): could "
320 "not delete mail: %s\n", strerror(status
));
322 return B_DELETE_MAIL_ACTION
;
327 return B_NO_MAIL_ACTION
;
329 // We have to rename the file
330 node_ref newParentRef
;
331 newParentRef
.device
= outRef
.device
;
332 newParentRef
.node
= outRef
.directory
;
334 BDirectory
newParent(&newParentRef
);
335 status_t status
= newParent
.InitCheck();
337 if (status
== B_OK
) {
338 int32 uniqueNumber
= 1;
340 workerName
= outRef
.name
;
341 if (uniqueNumber
> 1)
342 workerName
<< "_" << uniqueNumber
;
344 // TODO: support copying to another device!
346 status
= entry
.Rename(workerName
);
349 } while (status
== B_FILE_EXISTS
);
352 if (status
!= B_OK
) {
353 fprintf(stderr
, "BMailProtocol::NotifyHeaderFetched(): could not "
354 "rename mail (%s)! (should be: %s)\n", strerror(status
),
355 workerName
.String());
359 ref
.set_name(workerName
.String());
361 return B_MOVE_MAIL_ACTION
;
366 BMailProtocol::_NotifyBodyFetched(const entry_ref
& ref
, BFile
& file
,
367 BMessage
& attributes
)
369 for (int i
= 0; i
< fFilterList
.CountItems(); i
++)
370 fFilterList
.ItemAt(i
)->BodyFetched(ref
, file
, attributes
);
377 BInboundMailProtocol::BInboundMailProtocol(const BMailAccountSettings
& settings
)
379 BMailProtocol(settings
)
381 LoadFilters(fAccountSettings
.InboundSettings());
385 BInboundMailProtocol::~BInboundMailProtocol()
391 BInboundMailProtocol::MessageReceived(BMessage
* message
)
393 switch (message
->what
) {
394 case kMsgSyncMessages
:
396 NotiyMailboxSynchronized(SyncMessages());
403 message
->FindRef("ref", &ref
);
404 status_t status
= FetchBody(ref
);
407 if (message
->FindMessenger("target", &target
) != B_OK
)
410 BMessage
message(B_MAIL_BODY_FETCHED
);
411 message
.AddInt32("status", status
);
412 message
.AddRef("ref", &ref
);
413 target
.SendMessage(&message
);
417 case kMsgMarkMessageAsRead
:
420 message
->FindRef("ref", &ref
);
421 read_flags read
= (read_flags
)message
->FindInt32("read");
422 MarkMessageAsRead(ref
, read
);
426 case kMsgDeleteMessage
:
429 message
->FindRef("ref", &ref
);
434 case kMsgAppendMessage
:
437 message
->FindRef("ref", &ref
);
443 BMailProtocol::MessageReceived(message
);
450 BInboundMailProtocol::MarkMessageAsRead(const entry_ref
& ref
, read_flags flag
)
453 return write_read_attr(node
, flag
);
458 BInboundMailProtocol::AppendMessage(const entry_ref
& ref
)
465 BInboundMailProtocol::NotiyMailboxSynchronized(status_t status
)
467 for (int32 i
= 0; i
< CountFilter(); i
++)
468 FilterAt(i
)->MailboxSynchronized(status
);
475 BOutboundMailProtocol::BOutboundMailProtocol(
476 const BMailAccountSettings
& settings
)
478 BMailProtocol(settings
)
480 LoadFilters(fAccountSettings
.OutboundSettings());
484 BOutboundMailProtocol::~BOutboundMailProtocol()
490 BOutboundMailProtocol::MessageReceived(BMessage
* message
)
492 switch (message
->what
) {
493 case kMsgSendMessage
:
494 SendMessages(*message
, message
->FindInt64("bytes"));
498 BMailProtocol::MessageReceived(message
);